agent-council 0.1.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.
- checksums.yaml +7 -0
- data/DESIGN.md +378 -0
- data/INSTALL.md +98 -0
- data/LICENSE.txt +21 -0
- data/README.md +852 -0
- data/RELEASE_NOTES.md +25 -0
- data/code-review-agents.md +28 -0
- data/examples/configs/consolidated.yml +22 -0
- data/examples/configs/single.yml +10 -0
- data/examples/prompts/dnsruby-pull-221-prompt.md +4 -0
- data/examples/prompts/project-name-prompt.md +3 -0
- data/examples/prompts/recommend-model-ensemble-prompt.md +62 -0
- data/examples/prompts/review-docs-prompt.md +101 -0
- data/examples/prompts/review-latest-commit-prompt.md +46 -0
- data/examples/prompts/review-pull-request-prompt.md +91 -0
- data/examples/prompts/smoke-test-prompt.md +1 -0
- data/examples/prompts/state-of-the-code-base-prompt.md +172 -0
- data/examples/prompts/test-coverage-analysis-prompt.md +346 -0
- data/exe/agent-council +12 -0
- data/exe/pi-models +39 -0
- data/lib/agent_council/harnesses/pi_harness.rb +169 -0
- data/lib/agent_council/pi_models.rb +185 -0
- data/lib/agent_council/platform.rb +27 -0
- data/lib/agent_council/templates/analyst_format.md +12 -0
- data/lib/agent_council/templates/consolidate_prompt.md +72 -0
- data/lib/agent_council/version.rb +5 -0
- data/lib/agent_council/worker_pool.rb +217 -0
- data/lib/agent_council.rb +1220 -0
- metadata +84 -0
data/README.md
ADDED
|
@@ -0,0 +1,852 @@
|
|
|
1
|
+
# agent-council
|
|
2
|
+
|
|
3
|
+
Run one prompt through several AI coding agents at once, against your
|
|
4
|
+
own project, and get two things back: a **consolidated report** that is
|
|
5
|
+
better than any single agent's, and a **head-to-head comparison** of the
|
|
6
|
+
models and providers behind the agents, measured on speed, token usage,
|
|
7
|
+
cost, and quality.
|
|
8
|
+
|
|
9
|
+
agent-council runs the **same analytical prompt** through each agent
|
|
10
|
+
using the [Pi](https://github.com/earendil-works/pi) coding-agent harness,
|
|
11
|
+
with whatever mix of providers and models you choose. It saves each
|
|
12
|
+
agent's final response as a separate Markdown report and records how long
|
|
13
|
+
it took, how many tokens it used, and what it cost. A **consolidator**
|
|
14
|
+
agent then combines the reports into a findings report of consensus
|
|
15
|
+
findings, unique findings, and contradictions, and a companion report
|
|
16
|
+
that assesses what each agent contributed.
|
|
17
|
+
|
|
18
|
+
**New to Ruby? [Install agent-council from scratch](INSTALL.md)**
|
|
19
|
+
|
|
20
|
+
## Why use it
|
|
21
|
+
|
|
22
|
+
### A council of second opinions
|
|
23
|
+
|
|
24
|
+
- **Catch what one model misses.** Different models notice different
|
|
25
|
+
problems and weigh trade-offs differently; asking several surfaces
|
|
26
|
+
blind spots that no single answer reveals.
|
|
27
|
+
- **Get one report to read, not five.** The optional consolidator reads
|
|
28
|
+
every analyst report, checks their claims against your project where it
|
|
29
|
+
can, and writes a synthesis, so you can see where the models agree and
|
|
30
|
+
where they differ.
|
|
31
|
+
|
|
32
|
+
### A benchmark built from your own work
|
|
33
|
+
|
|
34
|
+
Public leaderboards tell you how models do on someone else's tasks.
|
|
35
|
+
agent-council tells you how they do on *yours*: your codebase, your
|
|
36
|
+
questions, your standards. Every run is a controlled experiment, with the
|
|
37
|
+
same prompt, the same repository, and the same tools at the same moment,
|
|
38
|
+
so the differences you see are differences in the models and in the
|
|
39
|
+
providers serving them.
|
|
40
|
+
|
|
41
|
+
- **Speed.** Every agent's wall-clock duration, side by side. Find out
|
|
42
|
+
which models answer in two minutes and which take twenty, and whether
|
|
43
|
+
the wait buys anything.
|
|
44
|
+
- **Tokens and cost.** Input, cached input, and output tokens, and dollar
|
|
45
|
+
cost where pi can price the model, per agent and in total. See whether
|
|
46
|
+
the model that costs ten times as much finds ten times as much.
|
|
47
|
+
- **Quality.** The reports sit side by side, labeled by source. The
|
|
48
|
+
consolidator shows which findings each model shared with the others,
|
|
49
|
+
which only it found, and where models contradicted each other, and its
|
|
50
|
+
*Agent performance* section assesses each agent's depth of research
|
|
51
|
+
(did it read the code, run commands, verify its claims?) and how much it
|
|
52
|
+
added, as opposed to noise or errors.
|
|
53
|
+
- **Providers, not just models.** Run the same model through different
|
|
54
|
+
providers, such as its maker's API and an aggregator, and compare their
|
|
55
|
+
latency, price, and reliability. Failures are recorded with their
|
|
56
|
+
reasons, so an unreliable provider shows up in the record.
|
|
57
|
+
- **Evidence that accumulates.** Each run's measurements are saved in a
|
|
58
|
+
machine-readable `run.json`. Over weeks of real work, those files
|
|
59
|
+
become a dataset for choosing your default model, your ensemble, and
|
|
60
|
+
your budget from your own results, not from marketing or hunches.
|
|
61
|
+
|
|
62
|
+
### Repeatable and cheap to set up
|
|
63
|
+
|
|
64
|
+
A prompt file and a short YAML config are all a run needs; every run's
|
|
65
|
+
reports, prompt, config, and measurements are saved together in a
|
|
66
|
+
timestamped directory, so a comparison can be rerun next month, against
|
|
67
|
+
next month's models.
|
|
68
|
+
|
|
69
|
+
The project is at an early stage; support for more harnesses than Pi,
|
|
70
|
+
such as Claude Code and Codex, is among the
|
|
71
|
+
[planned features](DESIGN.md#18-status-and-future-work), and will extend
|
|
72
|
+
these comparisons to the same model running under different harnesses. See
|
|
73
|
+
[`DESIGN.md`](DESIGN.md) for the rationale.
|
|
74
|
+
|
|
75
|
+
> **Between releases**, the documentation in the repository describes the
|
|
76
|
+
> next release, not the latest published one, so it may cover features
|
|
77
|
+
> (and a version) that are not yet in a released gem. The documentation
|
|
78
|
+
> installed with the gem matches the installed version.
|
|
79
|
+
|
|
80
|
+
## Quick start
|
|
81
|
+
|
|
82
|
+
A first run from scratch, using two models and a consolidator that
|
|
83
|
+
synthesizes their reports. The sections after this one cover each step
|
|
84
|
+
in detail.
|
|
85
|
+
|
|
86
|
+
1. **Install the prerequisites:** Ruby 3.3+ (or JRuby 10+) and the
|
|
87
|
+
[`pi` CLI](https://github.com/earendil-works/pi) (`pi --version`). See
|
|
88
|
+
[Prerequisites](#prerequisites), or [INSTALL.md](INSTALL.md) if you
|
|
89
|
+
need to install Ruby too.
|
|
90
|
+
2. **Set up credentials for at least one provider in pi** (see
|
|
91
|
+
[pi's documentation][pi-docs]), then list the models available to pi
|
|
92
|
+
(a listed model can still be one your plan doesn't include). Two
|
|
93
|
+
different providers give more diverse viewpoints, but two models from
|
|
94
|
+
one provider work too:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
pi --list-models
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
3. **Install the gem:**
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
gem install agent-council
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
4. **Go to the project you want analyzed:**
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
cd /path/to/the/project/you/want/analyzed
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
5. **Write a config** named `agent-council.yml` there, replacing the
|
|
113
|
+
placeholders with providers and models from step 2 (copy its
|
|
114
|
+
`provider` and `model` columns as they are). The
|
|
115
|
+
`consolidator` can be any model, including one of the agents:
|
|
116
|
+
|
|
117
|
+
```yaml
|
|
118
|
+
# agent-council.yml
|
|
119
|
+
agents:
|
|
120
|
+
- provider: <provider-1>
|
|
121
|
+
model: <model-1>
|
|
122
|
+
- provider: <provider-2>
|
|
123
|
+
model: <model-2>
|
|
124
|
+
consolidator:
|
|
125
|
+
provider: <provider-1>
|
|
126
|
+
model: <model-1>
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
6. **Write a prompt and run it** from that same directory (the prompt
|
|
130
|
+
file can live anywhere):
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
echo 'In one paragraph, what does this project do?' > what-is-this-prompt.md
|
|
134
|
+
agent-council what-is-this-prompt.md
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
This calls each configured model at your providers' usual rates. Any
|
|
138
|
+
files an agent reads, and the output of any commands it runs, go to
|
|
139
|
+
that agent's provider; see [Safety and privacy](#safety-and-privacy).
|
|
140
|
+
|
|
141
|
+
Each model's answer is saved as a Markdown file under
|
|
142
|
+
`agent-council-reports/<yyyy-mm-dd>/<hh-mm-ss>/reviews/`, and the
|
|
143
|
+
consolidated report is written to the run directory itself, split into a
|
|
144
|
+
`_findings.md` file (findings, contradictions, and overall assessment, with
|
|
145
|
+
no front matter or orchestration tables, so it can be pasted into an AI chat as is) and a
|
|
146
|
+
`_meta.md` file (front matter, tables, agents consulted, and agent
|
|
147
|
+
performance), or a single `_consolidated_...md` file if the model's report
|
|
148
|
+
couldn't be split; see
|
|
149
|
+
[What you get](#what-you-get). To add more models or change the
|
|
150
|
+
consolidator, see
|
|
151
|
+
[Discovering and configuring models](#discovering-and-configuring-models).
|
|
152
|
+
|
|
153
|
+
## Prerequisites
|
|
154
|
+
|
|
155
|
+
- Ruby 3.3 or later, or JRuby 10 or later (standard library only for the
|
|
156
|
+
tool itself; CI tests 3.3, 3.4, 4.0, JRuby 10.0 and the latest
|
|
157
|
+
JRuby)
|
|
158
|
+
- The [`pi` CLI](https://github.com/earendil-works/pi) installed
|
|
159
|
+
(`pi --version`; tested with pi 1.3.0 and 1.4.0)
|
|
160
|
+
- Credentials for at least one provider (several give more diverse
|
|
161
|
+
viewpoints), configured through pi itself (see
|
|
162
|
+
[pi's documentation][pi-docs])
|
|
163
|
+
- On Windows, WSL (e.g. Ubuntu): native Windows is not supported. Install
|
|
164
|
+
and run Ruby, pi, and agent-council inside WSL, from a WSL shell
|
|
165
|
+
([INSTALL.md](INSTALL.md) has the steps). Windows drives are reachable
|
|
166
|
+
at `/mnt/c/...`, but file access there is much slower than in the Linux
|
|
167
|
+
filesystem (e.g. `~/projects`). Set up pi's provider credentials inside
|
|
168
|
+
WSL too; WSL doesn't share them with Windows.
|
|
169
|
+
|
|
170
|
+
## Installation
|
|
171
|
+
|
|
172
|
+
With [the prerequisites](#prerequisites) in place (or following
|
|
173
|
+
[INSTALL.md](INSTALL.md) from scratch), install the gem to make the
|
|
174
|
+
`agent-council` command available on your RubyGems executable path:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
gem install agent-council
|
|
178
|
+
agent-council -h
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
The gem creates no config for you; it ships samples in `examples/configs/`. See
|
|
182
|
+
[Discovering and configuring models](#discovering-and-configuring-models)
|
|
183
|
+
to write one. To work on agent-council itself, see
|
|
184
|
+
[Development](#development).
|
|
185
|
+
|
|
186
|
+
### Finding the installed documentation and examples
|
|
187
|
+
|
|
188
|
+
The installed gem contains this README, [`INSTALL.md`](INSTALL.md),
|
|
189
|
+
[`DESIGN.md`](DESIGN.md), [`code-review-agents.md`](code-review-agents.md),
|
|
190
|
+
`RELEASE_NOTES.md`, and the sample prompts and configs under `examples/`,
|
|
191
|
+
all matching the installed version. The help output shows where they are
|
|
192
|
+
for the copy of `agent-council` you are actually running:
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
agent-council -h # see "Documentation (Local)" and "Examples (Local)"
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
To get the gem's directory in a shell variable:
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
AC_HOME=$(ruby <<'RUBY'
|
|
202
|
+
print Gem::Specification
|
|
203
|
+
.find_by_name('agent-council', '>= 0.a')
|
|
204
|
+
.full_gem_path
|
|
205
|
+
RUBY
|
|
206
|
+
)
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
If several versions are installed, this finds the newest, prereleases
|
|
210
|
+
included: the same one a plain `agent-council` command runs.
|
|
211
|
+
|
|
212
|
+
## Discovering and configuring models
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
pi --list-models # models of the providers you have credentials for
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
`pi --list-models` lists only the models of providers pi has
|
|
219
|
+
credentials for, not its whole catalog, so a provider missing from it
|
|
220
|
+
may just lack credentials. A listed model can still be unusable, e.g.
|
|
221
|
+
one your plan doesn't include. Credentials, and which one pi uses when
|
|
222
|
+
a provider has several, are pi's business; see
|
|
223
|
+
[pi's documentation][pi-docs].
|
|
224
|
+
|
|
225
|
+
Edit the config to choose the ensemble. The config is the optional second
|
|
226
|
+
argument; if omitted, `./agent-council.yml` in the current directory is used
|
|
227
|
+
(parent directories are not searched), else `~/.agent-council.yml` in your
|
|
228
|
+
home directory. It is an error if neither exists. Each entry becomes one
|
|
229
|
+
pi run with that `--provider` and `--model` (see
|
|
230
|
+
[How it works](#how-it-works-and-what-pi-is-told) for the full command), so no Ruby changes
|
|
231
|
+
are needed to add, remove, or swap models. A small config (replace the
|
|
232
|
+
providers and models with ones you have credentials for):
|
|
233
|
+
|
|
234
|
+
```yaml
|
|
235
|
+
# agent-council.yml
|
|
236
|
+
agents:
|
|
237
|
+
- provider: opencode-go
|
|
238
|
+
model: kimi-k2.7-code
|
|
239
|
+
- provider: openai
|
|
240
|
+
model: gpt-6.1-sol
|
|
241
|
+
consolidator: # optional; omit to skip consolidation
|
|
242
|
+
provider: opencode-go
|
|
243
|
+
model: kimi-k2.7-code
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Use at least two agents: a council of one gives a single viewpoint, and
|
|
247
|
+
consolidating a single report adds cost without adding anything.
|
|
248
|
+
|
|
249
|
+
The config must be a YAML mapping with a non-empty `agents` list. Each
|
|
250
|
+
agent, and the consolidator, needs string `provider` and `model` values
|
|
251
|
+
(quote any value YAML would read as something else, such as a number,
|
|
252
|
+
a date, or `yes`); other keys are ignored.
|
|
253
|
+
|
|
254
|
+
More samples are in [`examples/configs/`](examples/configs/), which is
|
|
255
|
+
included in the installed gem. For scripts and agents,
|
|
256
|
+
[`pi-models`](#occasional-utility-pi-models) lists the models in
|
|
257
|
+
machine-readable forms.
|
|
258
|
+
|
|
259
|
+
For a recommended code-review ensemble, see
|
|
260
|
+
[`code-review-agents.md`](code-review-agents.md). It is Markdown, not a
|
|
261
|
+
config file: copy its YAML block into your config.
|
|
262
|
+
|
|
263
|
+
An optional top-level `consolidator:` entry (provider + model, same
|
|
264
|
+
shape as an agent) runs after all agents finish. That model receives:
|
|
265
|
+
|
|
266
|
+
- the original prompt;
|
|
267
|
+
- the analyst reports in `reviews/`, each labeled with its source model;
|
|
268
|
+
- a list of the agents without a report, with each one's failure reason
|
|
269
|
+
(in a normal run);
|
|
270
|
+
- the instructions in `lib/agent_council/templates/consolidate_prompt.md`
|
|
271
|
+
in the gem's directory (`$AC_HOME`; see
|
|
272
|
+
[Finding the installed documentation and examples](#finding-the-installed-documentation-and-examples))
|
|
273
|
+
or a source checkout, where you can edit it to tune the consolidation.
|
|
274
|
+
|
|
275
|
+
agent-council saves its response as a report in the run dir itself (see
|
|
276
|
+
[What you get](#what-you-get) for its name). Remove the key to skip consolidation. To
|
|
277
|
+
consolidate a run that has already finished, see
|
|
278
|
+
[Consolidating a finished run](#consolidating-a-finished-run).
|
|
279
|
+
|
|
280
|
+
## Running
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
cd /path/to/the/repo/you/want/analyzed
|
|
284
|
+
agent-council /path/to/prompt.md
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
There is no option to choose the directory analyzed: Pi analyzes its **own
|
|
288
|
+
working directory**, which is the directory you run `agent-council` from. Run it from
|
|
289
|
+
the project you want analyzed; the prompt file can live anywhere, as can a
|
|
290
|
+
config given as an argument.
|
|
291
|
+
Reports land in `./agent-council-reports` under that working directory,
|
|
292
|
+
so each analyzed project gets its own reports tree. To put them
|
|
293
|
+
elsewhere, pass `-o DIR` / `--output-dir DIR`; a relative `DIR` is
|
|
294
|
+
resolved against the working directory. (An explicit `--output-dir` can't be
|
|
295
|
+
combined with `--consolidate`, which works on the reports of an existing
|
|
296
|
+
run and writes its consolidated report into that run's directory.)
|
|
297
|
+
|
|
298
|
+
```bash
|
|
299
|
+
# Uses ./agent-council.yml, else ~/.agent-council.yml
|
|
300
|
+
agent-council my-analysis-prompt.md
|
|
301
|
+
# Uses another config
|
|
302
|
+
agent-council my-analysis-prompt.md other-config.yml
|
|
303
|
+
# Writes reports under ./tmp/council
|
|
304
|
+
agent-council -o tmp/council my-analysis-prompt.md
|
|
305
|
+
# Usage, options, and any AGENT_COUNCIL_OPTS value
|
|
306
|
+
agent-council -h
|
|
307
|
+
# Version
|
|
308
|
+
agent-council -v
|
|
309
|
+
# See Consolidating a finished run
|
|
310
|
+
agent-council --consolidate agent-council-reports/2026-09-03/09-14-02
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
Relative paths are resolved from the working directory. agent-council
|
|
314
|
+
expands `~` itself only in `--output-dir`; in other paths, the shell
|
|
315
|
+
must expand it.
|
|
316
|
+
|
|
317
|
+
[`examples/`](examples/) holds sample prompts and configs — pure samples, not
|
|
318
|
+
used at runtime. `examples/prompts/` and `examples/configs/` are included in
|
|
319
|
+
the installed gem. The commands below use `$AC_HOME`, the installed gem's
|
|
320
|
+
directory (see [Finding the installed documentation and
|
|
321
|
+
examples](#finding-the-installed-documentation-and-examples)); in a source
|
|
322
|
+
checkout, set `AC_HOME` to the checkout's path and put its `exe/` on
|
|
323
|
+
your `PATH` (see [Development](#development)). They still analyze your
|
|
324
|
+
current directory, and the sample configs name specific providers and
|
|
325
|
+
models — copy and edit one if yours differ.
|
|
326
|
+
|
|
327
|
+
- `examples/prompts/state-of-the-code-base-prompt.md` — a real codebase-analysis
|
|
328
|
+
prompt; with `examples/configs/consolidated.yml` this is the full
|
|
329
|
+
ensemble:
|
|
330
|
+
|
|
331
|
+
```bash
|
|
332
|
+
agent-council \
|
|
333
|
+
"$AC_HOME/examples/prompts/state-of-the-code-base-prompt.md" \
|
|
334
|
+
"$AC_HOME/examples/configs/consolidated.yml"
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
- `examples/prompts/smoke-test-prompt.md` +
|
|
338
|
+
`examples/configs/single.yml` — a tiny, cheap prompt (one multiplication
|
|
339
|
+
question — enough to prove a real answer came back) and a one-model
|
|
340
|
+
config, for verifying your setup in seconds (the
|
|
341
|
+
[report-format addendum](#how-it-works-and-what-pi-is-told) may wrap
|
|
342
|
+
the number in a short report):
|
|
343
|
+
|
|
344
|
+
```bash
|
|
345
|
+
agent-council \
|
|
346
|
+
"$AC_HOME/examples/prompts/smoke-test-prompt.md" \
|
|
347
|
+
"$AC_HOME/examples/configs/single.yml"
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
- `examples/prompts/project-name-prompt.md` + `examples/configs/consolidated.yml` —
|
|
351
|
+
a small creative-writing prompt useful for spotting prompt-sensitivity
|
|
352
|
+
differences across models:
|
|
353
|
+
|
|
354
|
+
```bash
|
|
355
|
+
agent-council \
|
|
356
|
+
"$AC_HOME/examples/prompts/project-name-prompt.md" \
|
|
357
|
+
"$AC_HOME/examples/configs/consolidated.yml"
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
- `examples/prompts/recommend-model-ensemble-prompt.md` — a reusable prompt
|
|
361
|
+
for recommending a provider-diverse model ensemble for a task (agents
|
|
362
|
+
run [`pi-models`](#occasional-utility-pi-models), which is on your
|
|
363
|
+
`PATH` once the gem is installed, and otherwise say they need a model
|
|
364
|
+
list); its sample
|
|
365
|
+
code-review recommendation is in
|
|
366
|
+
[`examples/results/recommend-model-ensemble-code-review.md`](https://github.com/keithrbennett/agent-council/blob/main/examples/results/recommend-model-ensemble-code-review.md)
|
|
367
|
+
(generated output, in the source repository only — not in the gem; it
|
|
368
|
+
shares its title with, but is not, the curated
|
|
369
|
+
[`code-review-agents.md`](code-review-agents.md)).
|
|
370
|
+
- `examples/prompts/review-latest-commit-prompt.md` — a code-review prompt
|
|
371
|
+
for the latest commit (plus any uncommitted changes); run it from the
|
|
372
|
+
repository under review with a multi-model config.
|
|
373
|
+
- `examples/prompts/review-pull-request-prompt.md` — the same review for a
|
|
374
|
+
GitHub pull request, plus its unaddressed review comments and failing
|
|
375
|
+
checks. Check out the PR first (`gh pr checkout <number>`) and run from
|
|
376
|
+
that checkout; agents need an authenticated
|
|
377
|
+
[`gh`](https://cli.github.com/) and read the PR through it.
|
|
378
|
+
- `examples/prompts/review-docs-prompt.md` — a documentation review: checks
|
|
379
|
+
the README, other Markdown files, help output, code comments, and samples
|
|
380
|
+
against the code for accuracy, completeness, consistency, first-run
|
|
381
|
+
usability, and clarity (including duplication);
|
|
382
|
+
run it from the repository whose docs you want reviewed.
|
|
383
|
+
- `examples/prompts/test-coverage-analysis-prompt.md` — a line-coverage
|
|
384
|
+
analysis organized by the logical parts of the system, with gaps ranked by
|
|
385
|
+
risk and a ready-to-use prompt for each recommended fix. It reads
|
|
386
|
+
SimpleCov's `coverage/coverage.json` through
|
|
387
|
+
[cov-loupe](https://github.com/keithrbennett/cov-loupe) and runs no tests,
|
|
388
|
+
so run your full test suite first; it stops with an error if the coverage
|
|
389
|
+
data looks out of date.
|
|
390
|
+
|
|
391
|
+
### Setting your own defaults with `AGENT_COUNCIL_OPTS`
|
|
392
|
+
|
|
393
|
+
To use the same options on every run, put them in the
|
|
394
|
+
`AGENT_COUNCIL_OPTS` environment variable. agent-council inserts its
|
|
395
|
+
arguments before the command-line ones, so an option given on the command
|
|
396
|
+
line overrides the same option there:
|
|
397
|
+
|
|
398
|
+
```bash
|
|
399
|
+
export AGENT_COUNCIL_OPTS="--output-dir tmp/council"
|
|
400
|
+
agent-council my-analysis-prompt.md
|
|
401
|
+
# Overrides AGENT_COUNCIL_OPTS
|
|
402
|
+
agent-council --output-dir other-reports my-analysis-prompt.md
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
Its arguments are treated exactly as if typed first on the command line,
|
|
406
|
+
so set it with care: for example, an `--output-dir` there makes
|
|
407
|
+
`--consolidate` fail, as if both were typed on the command line. The value is split into
|
|
408
|
+
words like a shell would, but agent-council doesn't expand variables in
|
|
409
|
+
it: `~` works, but a literal `$HOME` stays literal. (In a double-quoted
|
|
410
|
+
`export`, your shell has already expanded it.) A malformed value, such as
|
|
411
|
+
one with an unclosed quote, makes every command fail, `-h` and `-v`
|
|
412
|
+
included, with a message naming `AGENT_COUNCIL_OPTS`.
|
|
413
|
+
|
|
414
|
+
### Stopping a run
|
|
415
|
+
|
|
416
|
+
Ctrl-C (or SIGTERM, SIGHUP, or SIGQUIT) stops the run, keeping reports
|
|
417
|
+
already written:
|
|
418
|
+
|
|
419
|
+
- Running agents, the consolidator included, get SIGTERM (pi then also
|
|
420
|
+
stops the commands it started) and a shared 5 seconds to exit before
|
|
421
|
+
they are killed. A killed agent can't stop the commands it started, so
|
|
422
|
+
those may keep running.
|
|
423
|
+
- A second SIGINT, SIGTERM, or SIGQUIT kills them at once; further SIGHUPs
|
|
424
|
+
are ignored.
|
|
425
|
+
- agent-council then dies by that signal, so a shell loop running it
|
|
426
|
+
stops too; for SIGQUIT it exits with status 131 instead of dumping core.
|
|
427
|
+
- A signal agent-council was started ignoring (e.g. SIGHUP under `nohup`)
|
|
428
|
+
stays ignored, and Ctrl-Z suspends agent-council but not the agents.
|
|
429
|
+
- Under JRuby, SIGQUIT is left to the JVM, which prints a thread dump,
|
|
430
|
+
and doesn't stop the run.
|
|
431
|
+
|
|
432
|
+
[`DESIGN.md`](DESIGN.md) §7 explains why it works this way.
|
|
433
|
+
|
|
434
|
+
### Consolidating a finished run
|
|
435
|
+
|
|
436
|
+
To consolidate a finished run later — say its consolidation failed, it
|
|
437
|
+
had no consolidator, or you want another model's synthesis — pass its
|
|
438
|
+
run dir:
|
|
439
|
+
|
|
440
|
+
```bash
|
|
441
|
+
agent-council --consolidate agent-council-reports/2026-09-03/09-14-02
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
This runs only the consolidator, over the analyst reports in that run's
|
|
445
|
+
`reviews/`, and writes its report (split into findings and meta files,
|
|
446
|
+
as in a normal run) into the same run dir, named as in a normal run, with the run's original `run_stamp` (its date and time, plus
|
|
447
|
+
any suffix). Exit status is 0 only if the consolidation succeeded.
|
|
448
|
+
|
|
449
|
+
- **Run it from the analyzed project's directory**, as for a normal run:
|
|
450
|
+
the consolidator is asked to check the reports' claims against the
|
|
451
|
+
current directory where it can.
|
|
452
|
+
- **The prompt and config are the run's own copies**, and the
|
|
453
|
+
consolidator is the one in the config copy:
|
|
454
|
+
- To try a different model, edit the copy's `consolidator:` (the copy
|
|
455
|
+
then no longer records the run's original consolidator).
|
|
456
|
+
- If the run had no consolidator, add a `consolidator:` entry to the
|
|
457
|
+
copy first; otherwise `--consolidate` exits with an error.
|
|
458
|
+
- Leave the copy's `agents:` exactly as they were (same order,
|
|
459
|
+
providers, and models): an agent counts as having no report when no
|
|
460
|
+
report carries its number, provider, and model.
|
|
461
|
+
- **The consolidation instructions are the current template's** (the
|
|
462
|
+
installed gem's, or a checkout's own), which may have changed since
|
|
463
|
+
the run.
|
|
464
|
+
- **Existing reports are kept.** If a file with the name the new
|
|
465
|
+
report would get, or the name of its `_findings` or `_meta` file, already
|
|
466
|
+
exists (as it does when the same model configuration, meaning harness,
|
|
467
|
+
provider, and model, consolidated the run before), nothing runs; rename
|
|
468
|
+
or delete the file or files the message lists to redo it. Reports
|
|
469
|
+
from different model configurations have different names and sit side
|
|
470
|
+
by side, so you can compare their syntheses.
|
|
471
|
+
- **The run needs at least one analyst report written by
|
|
472
|
+
agent-council**: the prompt and config copies are found through the
|
|
473
|
+
reports' front matter (`prompt_file` and `config_file`, with
|
|
474
|
+
`run_stamp` and `query` naming the consolidated report). A run where
|
|
475
|
+
every analyst failed, or that was interrupted before any report was
|
|
476
|
+
written, can't be consolidated.
|
|
477
|
+
- **Failure reasons aren't saved in the run dir**, so the consolidator
|
|
478
|
+
is told only which configured agents have no report, with a note that
|
|
479
|
+
the reason wasn't recorded.
|
|
480
|
+
|
|
481
|
+
### Time zone
|
|
482
|
+
|
|
483
|
+
Run dir names, report filenames, and the front matter's `timestamp` and
|
|
484
|
+
`consolidated_at` all use the **local time zone**. There is no
|
|
485
|
+
agent-council option to change it; instead, set the standard `TZ`
|
|
486
|
+
environment variable, which Ruby (like most programs) honors. Timestamps
|
|
487
|
+
always carry their UTC offset (`2026-09-02T16:21:43+00:00` in UTC), so
|
|
488
|
+
they stay unambiguous whatever the zone.
|
|
489
|
+
|
|
490
|
+
| Platform | One run in UTC | Value format |
|
|
491
|
+
|---|---|---|
|
|
492
|
+
| Linux, macOS, WSL (bash, zsh, fish) | `TZ=UTC agent-council prompt.md` | IANA name [[1]][tz-iana] |
|
|
493
|
+
| Windows PowerShell | `$env:TZ = 'UTC0'; agent-council prompt.md` | POSIX-style [[2]][tz-gnu] [[3]][tz-posix-db] [[4]][tz-ms] |
|
|
494
|
+
| Windows cmd | `set "TZ=UTC0" && agent-council prompt.md` | POSIX-style [[2]][tz-gnu] [[3]][tz-posix-db] [[4]][tz-ms] |
|
|
495
|
+
|
|
496
|
+
On Windows, `TZ` set this way lasts for the rest of the shell session.
|
|
497
|
+
Git Bash on Windows accepts the Linux syntax but runs Windows Ruby, so it
|
|
498
|
+
takes POSIX-style values.
|
|
499
|
+
|
|
500
|
+
**Finding the value to use:**
|
|
501
|
+
|
|
502
|
+
- **IANA names** (Linux, macOS, WSL): `Area/City`, such as
|
|
503
|
+
`America/Chicago` or `Europe/Berlin`, plus `UTC`. List them with
|
|
504
|
+
`ls /usr/share/zoneinfo`, or see the list on Wikipedia [[1]][tz-iana].
|
|
505
|
+
A misspelled name isn't reported: it silently falls back to UTC, so
|
|
506
|
+
check the timestamp in a report's front matter.
|
|
507
|
+
- **POSIX-style values** (native Windows): a zone abbreviation, its
|
|
508
|
+
hours **west** of UTC (so the sign is the reverse of the usual
|
|
509
|
+
offset), and an optional daylight saving abbreviation: `UTC0`,
|
|
510
|
+
`EST5EDT` (US Eastern), `PST8PDT` (US Pacific), `CET-1CEST`
|
|
511
|
+
(Central Europe). The GNU C Library manual explains the format with
|
|
512
|
+
examples [[2]][tz-gnu]; to find your zone's value, look up its IANA
|
|
513
|
+
name in the `posix_tz_db` table [[3]][tz-posix-db] and use the part
|
|
514
|
+
before the first comma (`America/Chicago` gives
|
|
515
|
+
`CST6CDT,M3.2.0,M11.1.0`, so use `CST6CDT`), since Windows doesn't
|
|
516
|
+
support the daylight saving rules after it and always follows US
|
|
517
|
+
rules instead [[4]][tz-ms]. These values also work on Linux and
|
|
518
|
+
macOS.
|
|
519
|
+
|
|
520
|
+
References:
|
|
521
|
+
|
|
522
|
+
1. [List of tz database time zones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) (Wikipedia)
|
|
523
|
+
2. [The TZ Variable](https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html) (GNU C Library manual)
|
|
524
|
+
3. `posix_tz_db`: [IANA names mapped to POSIX TZ strings](https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv)
|
|
525
|
+
4. `_tzset`: [Microsoft C runtime documentation](https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/tzset)
|
|
526
|
+
|
|
527
|
+
[tz-iana]: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
|
528
|
+
[tz-gnu]: https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
|
|
529
|
+
[tz-posix-db]: https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
|
|
530
|
+
[tz-ms]: https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/tzset
|
|
531
|
+
|
|
532
|
+
To always use a zone, set `TZ` in your shell profile (e.g.
|
|
533
|
+
`export TZ=UTC`), keeping in mind that this affects every program
|
|
534
|
+
started from that shell. The agents inherit `TZ` either way, so it also
|
|
535
|
+
changes the time they see.
|
|
536
|
+
|
|
537
|
+
## What you get
|
|
538
|
+
|
|
539
|
+
Each run creates one run directory, holding its inputs and reports,
|
|
540
|
+
day-bucketed
|
|
541
|
+
(`--consolidate` instead writes into the existing run directory it is
|
|
542
|
+
given):
|
|
543
|
+
|
|
544
|
+
```text
|
|
545
|
+
agent-council-reports/
|
|
546
|
+
2026-09-02/
|
|
547
|
+
16-21-43/
|
|
548
|
+
codebase-review.md # prompt copy
|
|
549
|
+
analyst_format.md # report-format addendum copy
|
|
550
|
+
consolidated.yml # config copy
|
|
551
|
+
run.json # every agent run's outcome, duration, and token usage
|
|
552
|
+
reviews/ # analyst reports
|
|
553
|
+
2026-09-02-16-21-43_codebase-review_01_pi_opencode-go_glm-5.3.md
|
|
554
|
+
2026-09-02-16-21-43_codebase-review_02_pi_opencode-go_kimi-k3.md
|
|
555
|
+
2026-09-02-16-21-43_codebase-review_03_pi_openai_gpt-6.1-sol.md
|
|
556
|
+
2026-09-02-16-21-43_codebase-review_04_pi_cursor_claude-sonnet-5-5-high.md
|
|
557
|
+
# consolidated report, if a consolidator is configured, normally in two
|
|
558
|
+
# files: the findings, ready to paste into a chat, and the run's
|
|
559
|
+
# metadata (a report that can't be split is one file, without the
|
|
560
|
+
# _findings or _meta suffix)
|
|
561
|
+
2026-09-02-16-21-43_codebase-review_consolidated_pi_opencode-go_glm-5.3_findings.md
|
|
562
|
+
2026-09-02-16-21-43_codebase-review_consolidated_pi_opencode-go_glm-5.3_meta.md
|
|
563
|
+
18-05-11/
|
|
564
|
+
...
|
|
565
|
+
2026-09-03/
|
|
566
|
+
09-14-02/
|
|
567
|
+
...
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
- **Run dir name**: `hh-mm-ss` inside a `yyyy-mm-dd` day bucket (local
|
|
571
|
+
time, second resolution). Pure time, nothing else — except that if that
|
|
572
|
+
name is already taken (two runs started in the same second, or local
|
|
573
|
+
time repeating when clocks fall back or are set back), the new run gets
|
|
574
|
+
`hh-mm-ss-2`, `-3`, ... instead, so each run has its own directory.
|
|
575
|
+
- **Time zone**: local by default; see [Time zone](#time-zone) to use
|
|
576
|
+
UTC or another zone.
|
|
577
|
+
- **Report filenames** carry everything else:
|
|
578
|
+
`<yyyy-mm-dd>-<hh-mm-ss>_<query-slug>_<agent-number>_<harness>_<provider>_<model>.md`,
|
|
579
|
+
so a report stays self-describing when you copy or attach it outside the
|
|
580
|
+
tree (a consolidated report has `consolidated` in place of
|
|
581
|
+
`<agent-number>`, and, if the report was split, ends in `_findings` or `_meta` before `.md`); `<hh-mm-ss>` includes the run dir's suffix, if any,
|
|
582
|
+
and `<provider>` and `<model>` are sanitized like the query slug below,
|
|
583
|
+
but keep their case. `<harness>` is currently always `pi`, the only
|
|
584
|
+
harness agent-council supports so far.
|
|
585
|
+
`<agent-number>` is the agent's 1-based position in the config's
|
|
586
|
+
`agents` list (`01`, `02`, ...), so every report has a unique name even
|
|
587
|
+
if the same provider/model is configured more than once. The query slug
|
|
588
|
+
is the prompt file name without its extension, minus any trailing
|
|
589
|
+
`-prompt` or `_prompt` in any case (`codebase-review-prompt.md` and
|
|
590
|
+
`codebase-review_prompt.md` both become `codebase-review`), lowercased, with each run of characters
|
|
591
|
+
other than ASCII letters, digits, `.`, `_`, and `-` replaced by `-` and
|
|
592
|
+
leading or trailing `-` and `.` dropped (`My Prompt (draft).md` becomes
|
|
593
|
+
`my-prompt-draft`); a name left empty becomes `prompt`.
|
|
594
|
+
- **Day buckets** keep the reports directory itself navigable when you have hundreds
|
|
595
|
+
of runs.
|
|
596
|
+
- Each report file, except a consolidated report's `_findings.md`, begins with a small **YAML front matter** block,
|
|
597
|
+
written by the orchestrator (never by the model), identifying the
|
|
598
|
+
report (what was measured about its run is in `run.json`, below):
|
|
599
|
+
- in every report: `role` (`analyst` or `consolidator`), `timestamp`
|
|
600
|
+
(unquoted ISO 8601), `query` (the query slug), `harness`, `provider`, `model`,
|
|
601
|
+
`prompt_file` and `config_file` (the names of
|
|
602
|
+
the run dir's input copies), `config_source` (where the config was
|
|
603
|
+
found, with `~` for the home directory; informational only) and
|
|
604
|
+
`run_stamp` (the report filenames' date-time prefix, with the run
|
|
605
|
+
dir's suffix, if any);
|
|
606
|
+
- in analyst reports: `agent_index` (the agent number, as an integer);
|
|
607
|
+
- in consolidated reports: `sources` (the analyst labels that were
|
|
608
|
+
synthesized) and `consolidated_at` (when the
|
|
609
|
+
consolidation ran; with `--consolidate`, possibly long after
|
|
610
|
+
`timestamp`, the run's start).
|
|
611
|
+
|
|
612
|
+
- The run dir's **`run.json`** records every agent run, for tools and
|
|
613
|
+
for analysis across many runs: `analysts` and `consolidations`, one
|
|
614
|
+
entry per run with its `agent_index` (analysts only), `harness`,
|
|
615
|
+
`provider`, `model`, `ok`, `duration_seconds`, `usage`, and `report` (its
|
|
616
|
+
path in the run dir; for a split consolidation, the `_findings.md` file)
|
|
617
|
+
or `error`; a split consolidation also has `meta_report`, the `_meta.md`
|
|
618
|
+
file, which has the front matter; `total_usage`, the
|
|
619
|
+
entries' summed usage, whose `cost` is included only if every summed
|
|
620
|
+
entry's cost is known; and `total_usage_runs`, how many entries reported
|
|
621
|
+
usage (and so are in the total). Failed runs are included, since their
|
|
622
|
+
tokens were spent.
|
|
623
|
+
It is written once the reviews finish and updated after each
|
|
624
|
+
consolidation, including each `--consolidate`; a `--consolidate` of a
|
|
625
|
+
run dir without a readable `run.json` warns and writes none.
|
|
626
|
+
|
|
627
|
+
`usage` is the model's token usage, summed over every request of the
|
|
628
|
+
run, as reported by the harness: `input` (excluding cached input),
|
|
629
|
+
`cache_read`, `cache_write`, and `output` token counts, plus `cost` in
|
|
630
|
+
US dollars when the harness could price the run (pi uses its own price
|
|
631
|
+
table, so models missing from it have no cost). It is `null` when the
|
|
632
|
+
provider reports no usage. Providers count tokens somewhat differently
|
|
633
|
+
(reasoning tokens, for example), so compare counts across providers
|
|
634
|
+
only roughly.
|
|
635
|
+
|
|
636
|
+
`--consolidate` relies on the analysts' `prompt_file`, `config_file`,
|
|
637
|
+
`run_stamp`, and `query`, and on `agent_index` to tell which configured
|
|
638
|
+
agents have no report. Reports are identified by their front matter,
|
|
639
|
+
not by filename parsing, so `.md` files in `reviews/` without
|
|
640
|
+
`provider` and `model` front matter are ignored.
|
|
641
|
+
- Below the front matter, the orchestrator adds a metadata table
|
|
642
|
+
summarizing its main fields and its run's duration and token usage
|
|
643
|
+
(for consolidated reports, under a `# Consolidated Report` title and a
|
|
644
|
+
`### Prompt:` line, and followed by a `### Sources` table giving each
|
|
645
|
+
source's duration, input (cached included), cached input, output, and
|
|
646
|
+
cost, from `run.json`), followed by the
|
|
647
|
+
model's final message, minus any top-level `#` heading the message
|
|
648
|
+
starts with. The consolidator is asked to put a line containing only `=== META ===`
|
|
649
|
+
between its findings and its `Agent Consultants` and `Agent performance`
|
|
650
|
+
sections, and the report is split there: the text after the marker stays
|
|
651
|
+
with this header and front matter in the `_meta.md` file, and the text
|
|
652
|
+
before it goes to the `_findings.md` file under a `# Consolidated Findings`
|
|
653
|
+
title, a few lines identifying the run (its stamp and query, the prompt
|
|
654
|
+
file, and the consolidator and time), and a legend of the agents (number,
|
|
655
|
+
harness, provider, model). If
|
|
656
|
+
the marker is missing, repeated, inside a code fence, or not followed by
|
|
657
|
+
the `Agent Consultants` heading, or the report no longer starts with the
|
|
658
|
+
header written to it, the report is left unsplit, under the unsuffixed
|
|
659
|
+
name, and a warning says why.
|
|
660
|
+
- The copied prompt, config, and report-format addendum keep an analyst
|
|
661
|
+
run's inputs recoverable after the fact. The pi and agent-council
|
|
662
|
+
versions, the scaffolding text appended to pi's system prompt, and the
|
|
663
|
+
consolidation template are not recorded.
|
|
664
|
+
- The prompt and config copies keep their own file names (e.g.
|
|
665
|
+
`single.yml`), so the prompt, the config, and `analyst_format.md` must
|
|
666
|
+
have different file names, and none can be named `reviews`; a run that
|
|
667
|
+
would break either rule stops before starting.
|
|
668
|
+
|
|
669
|
+
Each run starts by printing its config, prompt, and run directory
|
|
670
|
+
(`Run Dir: agent-council-reports/2026-09-03/09-14-02`), then its agents
|
|
671
|
+
under `Review Agents (N):` and, if configured, `Consolidator Agent:`;
|
|
672
|
+
these labels also name the harness (e.g. `#2 pi / openai / gpt-6.1-sol`).
|
|
673
|
+
You can open the run dir while agents are still working, or after a
|
|
674
|
+
Ctrl-C (see [Stopping a run](#stopping-a-run)). Other access patterns:
|
|
675
|
+
|
|
676
|
+
```bash
|
|
677
|
+
# Last run by name: usually the newest
|
|
678
|
+
ls -d agent-council-reports/*/* | tail -1
|
|
679
|
+
# Today's runs
|
|
680
|
+
ls agent-council-reports/$(date +%F)/
|
|
681
|
+
# Every analyst report for one question, all runs
|
|
682
|
+
ls agent-council-reports/*/*/reviews/*codebase-review*
|
|
683
|
+
```
|
|
684
|
+
|
|
685
|
+
While the agents run, a `Review Progress:` section prints one line per
|
|
686
|
+
agent as it finishes: `✓` or `✗`, its duration, its label (e.g.
|
|
687
|
+
`#2 openai / gpt-6.1-sol`) and, for a failure, the reason on the line
|
|
688
|
+
below. When all reviews finish, a `Reviews` table shows which models
|
|
689
|
+
succeeded, how long each took (`HH:MM:SS`) and their token usage in
|
|
690
|
+
`In`, `Cached`, `Out`, and `Cost` columns (`In` counts cached input too;
|
|
691
|
+
`-` when unknown; failed runs show what they used), with the failures'
|
|
692
|
+
reasons listed below it under `Errors:`. A
|
|
693
|
+
`--- Reviews complete (N/M succeeded; <total usage>) ---` line follows,
|
|
694
|
+
e.g. `2.1M in (2.0M cached) / 32.7k out, $0.18`. The total's cost is
|
|
695
|
+
shown only when every counted analyst's cost is known, and the total
|
|
696
|
+
notes `(from K of M agents)` when some reported no usage (as some
|
|
697
|
+
providers don't). With a consolidator,
|
|
698
|
+
the `Consolidation Report (in <run dir>):` heading (with
|
|
699
|
+
`--consolidate`, `(in <run dir>, from N review(s)):`) then prints while it
|
|
700
|
+
runs, its result row when it finishes, and finally `--- Consolidation
|
|
701
|
+
complete ---` (or `--- Consolidation error ---`). One model's failure
|
|
702
|
+
does not affect the others. Exit status is 0 only if every analyst
|
|
703
|
+
agent succeeded; the consolidator's result doesn't affect it.
|
|
704
|
+
|
|
705
|
+
Output paths are printed relative to the current working directory (e.g.
|
|
706
|
+
`agent-council-reports/2026-09-04/21-39-01/reviews`), not to where
|
|
707
|
+
agent-council is installed. Paths outside the working directory (such
|
|
708
|
+
as an `--output-dir` elsewhere) are printed absolute, as is a default
|
|
709
|
+
config's (`Config: [default] /path/to/agent-council.yml`), to show
|
|
710
|
+
which default was picked up.
|
|
711
|
+
|
|
712
|
+
## How it works (and what pi is told)
|
|
713
|
+
|
|
714
|
+
- Every analyst agent receives the **same bytes**: the prompt file's
|
|
715
|
+
contents (with one trailing newline removed), a blank line, and the
|
|
716
|
+
report-format addendum
|
|
717
|
+
(`lib/agent_council/templates/analyst_format.md`, copied into each run
|
|
718
|
+
dir), piped to pi on stdin as the prompt. No roles, no per-model customization. The addendum asks for a
|
|
719
|
+
Markdown report with `##` section headings, which can conflict with a
|
|
720
|
+
prompt that asks for some other output form (the smoke-test prompt's
|
|
721
|
+
"Reply with just the number, then one sentence explaining how you got
|
|
722
|
+
it.", for example); models usually reconcile the two. (The
|
|
723
|
+
consolidator gets its own prompt; see
|
|
724
|
+
[Discovering and configuring models](#discovering-and-configuring-models).)
|
|
725
|
+
- Each agent runs as
|
|
726
|
+
`pi -p --mode json --no-session --tools read,grep,find,ls,bash
|
|
727
|
+
--provider P --model M --append-system-prompt <scaffolding>`.
|
|
728
|
+
- `--no-session` keeps runs independent: no conversation state leaks
|
|
729
|
+
between ensemble members.
|
|
730
|
+
- `--tools` is an allowlist for pi's built-in, extension, and custom
|
|
731
|
+
tools: `bash` remains for investigation (`git log`, dependency
|
|
732
|
+
inspection, ...), while file-editing tools and unlisted extension and
|
|
733
|
+
custom tools are unavailable, as are MCP tools. The allowlist is the
|
|
734
|
+
only enforced restriction (see [Safety and privacy](#safety-and-privacy)). A fixed
|
|
735
|
+
scaffolding text appended to the system prompt (identical for all
|
|
736
|
+
agents, the consolidator included, except the scratch path) tells agents
|
|
737
|
+
not to modify project files, git state, software, or configuration, or
|
|
738
|
+
start persistent services (they get a scratch directory for temporary
|
|
739
|
+
files), and
|
|
740
|
+
not to run tests, builds, or similar commands, which can collide between
|
|
741
|
+
concurrent analysts, unless the prompt permits them (as
|
|
742
|
+
`examples/prompts/review-latest-commit-prompt.md` does for tests and
|
|
743
|
+
linters); where such a command isn't permitted but would help, the
|
|
744
|
+
agent describes what it would run instead. The full text is
|
|
745
|
+
`scaffold_text` in `lib/agent_council/harnesses/pi_harness.rb`;
|
|
746
|
+
[`DESIGN.md`](DESIGN.md) §10 explains the rules.
|
|
747
|
+
- Each agent gets its own disposable temp directory (exposed via `TMPDIR`
|
|
748
|
+
and named in the scaffolding), deleted after the run. After Ctrl-C, a
|
|
749
|
+
directory can be left behind if a second signal stops agent-council at
|
|
750
|
+
once, or if cleanup after a killed agent doesn't finish in time.
|
|
751
|
+
- Otherwise pi behaves normally: it loads context files such as
|
|
752
|
+
`AGENTS.md` and `CLAUDE.md` as in any pi run, and the analyzed repo's
|
|
753
|
+
`.pi` project resources only if pi already trusts the project
|
|
754
|
+
(agent-council passes no `--approve`). See
|
|
755
|
+
[pi's documentation][pi-docs] for what loads from where.
|
|
756
|
+
- The final response is read from pi's JSONL event stream. pi exits 0
|
|
757
|
+
even when the provider rejects the request (e.g. Copilot's
|
|
758
|
+
`model_not_available_for_integrator`) or the output is cut off;
|
|
759
|
+
agent-council detects these in the event stream and reports them as
|
|
760
|
+
failures, not reports. [`DESIGN.md`](DESIGN.md) §13 has the details.
|
|
761
|
+
|
|
762
|
+
## Safety and privacy
|
|
763
|
+
|
|
764
|
+
agent-council does not sandbox the agents. Before running it, know that:
|
|
765
|
+
|
|
766
|
+
- **Agents have a shell.** Each agent, the consolidator included, gets pi's
|
|
767
|
+
`bash` tool, running as you, in the directory you run from, with your
|
|
768
|
+
environment (including any API keys in it; agent-council only sets
|
|
769
|
+
`TMPDIR`), your file permissions, and your network access. Of pi's
|
|
770
|
+
built-in tools, only `edit` and `write` (and the Windows-only
|
|
771
|
+
`powershell`) are withheld. The read-only rules described above are
|
|
772
|
+
instructions in the system prompt, which a model can ignore or misapply.
|
|
773
|
+
- **MCP servers still start.** agent-council doesn't pass `--no-mcp`,
|
|
774
|
+
so pi starts or connects the MCP servers you have configured for every
|
|
775
|
+
agent, as you. Their tools can't be called (tested with pi 1.4.0):
|
|
776
|
+
the `--tools` allowlist names none of them, nor pi's `codemode` and
|
|
777
|
+
`tool_search` tools, which reach them indirectly. A server that does
|
|
778
|
+
something merely by starting still does it.
|
|
779
|
+
- **The analyzed repository can steer the agents.** Agents read the
|
|
780
|
+
repository's files, and pi loads its context files (such as
|
|
781
|
+
`AGENTS.md`) and, if the project is trusted, its `.pi` resources, so
|
|
782
|
+
text in the repository can try to direct what the agents run (prompt
|
|
783
|
+
injection). Prompts that permit tests,
|
|
784
|
+
such as `examples/prompts/review-latest-commit-prompt.md`, run the
|
|
785
|
+
project's own code.
|
|
786
|
+
- **Your code goes to every configured provider.** Whatever an agent reads,
|
|
787
|
+
and the output of whatever it runs, is sent to that agent's provider. The
|
|
788
|
+
consolidator's provider receives the prompt and all reports, plus
|
|
789
|
+
anything the consolidator itself reads or runs. Check those providers'
|
|
790
|
+
data policies before analyzing private code.
|
|
791
|
+
- **Reports stay in the analyzed project by default.** They are written
|
|
792
|
+
under `agent-council-reports/` in the working directory, unless you give
|
|
793
|
+
an `--output-dir`; add that directory to the project's `.gitignore` if
|
|
794
|
+
you don't want them committed.
|
|
795
|
+
|
|
796
|
+
Run agent-council only on repositories you trust, or inside a container, VM,
|
|
797
|
+
or disposable checkout that holds no credentials you aren't willing to
|
|
798
|
+
expose.
|
|
799
|
+
|
|
800
|
+
## Limitations (deliberate)
|
|
801
|
+
|
|
802
|
+
No retries or timeouts of agent-council's own (pi itself may retry
|
|
803
|
+
transient provider failures), no ranking
|
|
804
|
+
or scoring of reports
|
|
805
|
+
(beyond the optional consolidator's synthesis), no manifests or indexes —
|
|
806
|
+
the directory layout is the index. See [`DESIGN.md`](DESIGN.md) §18–19.
|
|
807
|
+
|
|
808
|
+
## Stability
|
|
809
|
+
|
|
810
|
+
This is a 0.x release. The config format, command-line interface, run
|
|
811
|
+
directory layout, and report front matter may change incompatibly before 1.0.
|
|
812
|
+
|
|
813
|
+
## Development
|
|
814
|
+
|
|
815
|
+
In a git checkout (the gemspec lists files with `git ls-files`),
|
|
816
|
+
`./exe/agent-council` and `./exe/pi-models` are equivalent to the installed `agent-council` and
|
|
817
|
+
`pi-models`. Agents analyze the working directory, so running
|
|
818
|
+
`./exe/agent-council` from the checkout analyzes agent-council itself; to
|
|
819
|
+
analyze another project, `cd` there and run the checkout's executable by
|
|
820
|
+
its full path. Sample prompts such as `recommend-model-ensemble-prompt.md`
|
|
821
|
+
expect `pi-models` on your `PATH`; to use them from a checkout, add its
|
|
822
|
+
`exe/` directory (`export PATH="/path/to/agent-council/exe:$PATH"`).
|
|
823
|
+
|
|
824
|
+
Setup, tests, lint, the pre-commit hook, and the security audit are
|
|
825
|
+
described in [`CONTRIBUTING.md`](https://github.com/keithrbennett/agent-council/blob/main/CONTRIBUTING.md)
|
|
826
|
+
in the source repository. Before submitting a pull request, open an
|
|
827
|
+
issue and wait for explicit approval; `CONTRIBUTING.md` describes the
|
|
828
|
+
process.
|
|
829
|
+
|
|
830
|
+
## Occasional utility: `pi-models`
|
|
831
|
+
|
|
832
|
+
To choose models yourself, use `pi --list-models` (see
|
|
833
|
+
[Discovering and configuring models](#discovering-and-configuring-models)).
|
|
834
|
+
The gem also includes `pi-models`, which lists the same kind of
|
|
835
|
+
provider/model pairs in forms meant for scripts and agents; the sample
|
|
836
|
+
`recommend-model-ensemble-prompt.md` has its agents run it. They differ in
|
|
837
|
+
two ways:
|
|
838
|
+
|
|
839
|
+
- **Output.** `pi --list-models` prints a table for people. `pi-models` prints a table, JSON with pi's model fields
|
|
840
|
+
(`--json`, for `jq`), or one `provider/id` per line (`--ids`, for shell
|
|
841
|
+
loops), and exits non-zero with a clear message if pi is missing or
|
|
842
|
+
fails. `pi-models -h` lists the options and the JSON fields. In a config
|
|
843
|
+
entry, its `provider` is `provider` and its `id` is `model`.
|
|
844
|
+
- **Source.** `pi-models` asks pi over its RPC interface instead of running
|
|
845
|
+
`pi --list-models`, so its list can include models that
|
|
846
|
+
`pi --list-models` omits (e.g. extra `github-copilot` models), and those
|
|
847
|
+
may not be usable on your account.
|
|
848
|
+
|
|
849
|
+
`pi-models` requires `pi` and is on your `PATH` once the gem is installed;
|
|
850
|
+
like agent-council, it needs WSL on Windows.
|
|
851
|
+
|
|
852
|
+
[pi-docs]: https://github.com/earendil-works/pi/tree/main/packages/coding-agent/docs
|