teamrunner 0.0.2__tar.gz → 0.0.3__tar.gz
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.
- {teamrunner-0.0.2 → teamrunner-0.0.3}/.github/ISSUE_TEMPLATE/bug_report.yml +1 -1
- {teamrunner-0.0.2 → teamrunner-0.0.3}/.github/ISSUE_TEMPLATE/question.yml +1 -1
- {teamrunner-0.0.2 → teamrunner-0.0.3}/.github/workflows/tests.yml +9 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/CHANGELOG.md +24 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/PKG-INFO +32 -136
- teamrunner-0.0.3/PREVIEW.md +128 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/README.md +31 -135
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/fact_checked/against.md +0 -1
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/fact_checked/chair.md +3 -3
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/fact_checked/fact_checker.md +4 -4
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/fact_checked/for.md +0 -1
- teamrunner-0.0.3/examples/fact_checked/judge.md +20 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/fact_checked/sandbox.md +1 -1
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/fact_checked/team.yaml +2 -0
- teamrunner-0.0.3/examples/fact_checked/web.md +19 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/hiring_committee/models/member.yaml +3 -3
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/hiring_committee/team.yaml +1 -1
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/multi_agent_debate/against.md +0 -1
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/multi_agent_debate/for.md +0 -1
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/multi_agent_debate/judge.md +0 -1
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/multi_agent_debate/team.yaml +2 -0
- teamrunner-0.0.3/examples/orchestrators_lite/models/engineer.yaml +7 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/orchestrators_lite/team.yaml +3 -3
- teamrunner-0.0.3/examples/reference_check/catalogue.md +19 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/reference_check/context_checker.md +3 -2
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/reference_check/editor.md +4 -2
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/reference_check/intake.md +1 -1
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/reference_check/metadata_checker.md +11 -5
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/reference_check/reader.md +7 -2
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/reference_check/team.yaml +2 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/round_robin/01_for.md +0 -1
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/round_robin/02_against.md +0 -1
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/round_robin/03_judge.md +0 -1
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/round_robin/team.yaml +2 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/pyproject.toml +1 -1
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/__init__.py +1 -1
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/authoring/AGENTS.md +6 -1
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/build.py +20 -12
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/checks.py +109 -43
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/console.py +22 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/ir.py +18 -1
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/litellm_model.py +14 -1
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/new.py +2 -2
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/run.py +4 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/runs.py +3 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/schemas/member.schema.json +2 -2
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/schemas/model_profile.schema.json +2 -2
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/schemas/team.schema.json +2 -2
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/show.py +4 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/validate.py +14 -2
- {teamrunner-0.0.2 → teamrunner-0.0.3}/tests/test_new.py +2 -1
- {teamrunner-0.0.2 → teamrunner-0.0.3}/tests/test_run.py +112 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/tests/test_show.py +11 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/tests/test_validate.py +29 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/uv.lock +1 -1
- teamrunner-0.0.2/examples/fact_checked/judge.md +0 -19
- teamrunner-0.0.2/examples/fact_checked/web.md +0 -13
- teamrunner-0.0.2/examples/orchestrators_lite/models/engineer.yaml +0 -7
- teamrunner-0.0.2/examples/reference_check/catalogue.md +0 -22
- {teamrunner-0.0.2 → teamrunner-0.0.3}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/.github/workflows/publish.yml +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/.gitignore +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/CLA.md +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/CONTRIBUTING.md +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/LICENSE +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/NOTICE +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/SECURITY.md +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/LICENSE +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/fact_checked/.gitignore +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/hiring_committee/chair.md +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/hiring_committee/chen.md +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/hiring_committee/clerk.md +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/hiring_committee/diaz.md +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/hiring_committee/okafor.md +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/multi_agent_debate/.gitignore +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/multi_agent_debate/chair.md +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/orchestrators_lite/.gitignore +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/orchestrators_lite/chair.md +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/orchestrators_lite/derek.md +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/orchestrators_lite/emma.md +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/orchestrators_lite/lily.md +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/orchestrators_lite/noah.md +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/orchestrators_lite/zoe.md +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/reference_check/chair.md +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/reference_check/library.md +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/examples/round_robin/.gitignore +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/__main__.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/authoring/LICENSE +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/authoring/__init__.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/builtin_tools.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/cli.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/describe.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/desk.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/engine.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/environment.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/events.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/explain.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/flow.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/gather.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/ids.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/inputs.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/keys.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/loader.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/minutes.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/model.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/prices.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/problems.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/rehearsal.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/runfolder.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/sandbox/__init__.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/sandbox/run.js +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/schema_check.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/tool_registry.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/turns.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/src/teamrunner/vocabulary.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/tests/test_authoring.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/tests/test_engine.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/tests/test_explain.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/tests/test_flow.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/tests/test_minutes.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/tests/test_prices.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/tests/test_runs.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/tests/test_sandbox.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/tests/test_tools.py +0 -0
- {teamrunner-0.0.2 → teamrunner-0.0.3}/tests/test_turns.py +0 -0
|
@@ -68,3 +68,12 @@ jobs:
|
|
|
68
68
|
teamrunner explain debate
|
|
69
69
|
teamrunner run debate --rehearse -m "Should cities ban cars from their centres?"
|
|
70
70
|
teamrunner runs debate
|
|
71
|
+
|
|
72
|
+
# The website's tutorial (teamrunner.ai/tutorial.html), replayed with this build:
|
|
73
|
+
# a change that would break the tutorial fails here, before it is released
|
|
74
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
75
|
+
with:
|
|
76
|
+
repository: teamrunner/teamrunner.ai
|
|
77
|
+
path: website
|
|
78
|
+
- name: The website's tutorial
|
|
79
|
+
run: python website/tests/test_tutorial.py website/tutorial.html
|
|
@@ -4,6 +4,30 @@ TeamRunner is in preview: 0.0.x versions are a soft launch, and until 0.1.0
|
|
|
4
4
|
is announced a version may change in ways that break teams and run folders
|
|
5
5
|
made with an earlier one. Each such change is listed here.
|
|
6
6
|
|
|
7
|
+
## 0.0.3
|
|
8
|
+
|
|
9
|
+
- **Backup models**: `model:` and `default_model:` may name several models,
|
|
10
|
+
separated by commas, in order of preference
|
|
11
|
+
(`default_model: openai/gpt-6-luna, anthropic/claude-sonnet-4-5`). Before the
|
|
12
|
+
first turn each member gets the first one available, for the whole run; the
|
|
13
|
+
console says so whenever a member is not on its first choice, and `run.json`,
|
|
14
|
+
`events.jsonl` and `teamrunner runs` record it. A profile's `name:` still
|
|
15
|
+
names one model.
|
|
16
|
+
- The examples name their model once, as `default_model:` in `team.yaml`.
|
|
17
|
+
- All six examples use Gemma 4 31B through OpenRouter with one API key.
|
|
18
|
+
The fact checker reads public sources instead of requiring Brave Search;
|
|
19
|
+
reference lookups use Crossref without a catalogue key. Reference lists
|
|
20
|
+
and findings are shared in the meeting messages so the next checker and
|
|
21
|
+
the editor can read them.
|
|
22
|
+
- Gemma 4 tool calls on OpenRouter no longer compete with strict JSON
|
|
23
|
+
formatting: during tool use the final format is requested in the prompt,
|
|
24
|
+
and the runner still validates the declared outputs.
|
|
25
|
+
- The README's tutorial and its five ideas hold only what works today; what is
|
|
26
|
+
designed but not built yet (experiments, the whiteboard) is in `PREVIEW.md`.
|
|
27
|
+
The README installs with uv or pip and needs one key.
|
|
28
|
+
- Comments in the examples, and the `.gitignore` `teamrunner new` writes, no
|
|
29
|
+
longer cite internal design notes.
|
|
30
|
+
|
|
7
31
|
## 0.0.2 — the first preview
|
|
8
32
|
|
|
9
33
|
What the roadmap calls 0.1, the org package: a folder of text files that gets
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: teamrunner
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.3
|
|
4
4
|
Summary: The experimentation platform for agent organizations — run multi-agent orchestrations and factorial experiments entirely from text files.
|
|
5
5
|
Project-URL: Homepage, https://github.com/teamrunner/teamrunner
|
|
6
6
|
Project-URL: Repository, https://github.com/teamrunner/teamrunner
|
|
@@ -53,7 +53,7 @@ experiments/advocate_model/ [v0.2]
|
|
|
53
53
|
└── experiment.yaml ← base: ../../debate — GPT vs. Claude as advocate, 20 replications
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
> Everything unmarked
|
|
56
|
+
> Everything unmarked works today, in the preview. Marked parts are designed but not built yet: **[v0.2]** arrives with experiments; **[v0.3]** with richer organizations (managers, private information, subteams, parallel work).
|
|
57
57
|
|
|
58
58
|
```bash
|
|
59
59
|
teamrunner run debate --message "Remote work makes teams more productive"
|
|
@@ -68,13 +68,13 @@ No Python. No graph-building API. No framework vocabulary. If you can edit a tex
|
|
|
68
68
|
- [Why we built it](#why-we-built-it)
|
|
69
69
|
- [The five ideas](#the-five-ideas)
|
|
70
70
|
- [Tutorial: your first debate in 10 minutes](#tutorial-your-first-debate-in-10-minutes)
|
|
71
|
-
- [Tutorial part 2: your first experiment](#tutorial-part-2-your-first-experiment)
|
|
72
71
|
- [What lands in a run folder](#what-lands-in-a-run-folder)
|
|
73
72
|
- [What your runs keep, and where your words go](#what-your-runs-keep-and-where-your-words-go)
|
|
74
73
|
- [Going further: the worked examples](#going-further-the-worked-examples)
|
|
75
74
|
- [What TeamRunner is not](#what-teamrunner-is-not)
|
|
76
75
|
- [Status and roadmap](#status-and-roadmap)
|
|
77
76
|
- [Questions, bugs and ideas](#questions-bugs-and-ideas)
|
|
77
|
+
- [What's coming](PREVIEW.md): designed, not built yet
|
|
78
78
|
|
|
79
79
|
---
|
|
80
80
|
|
|
@@ -142,7 +142,7 @@ not your own opinion of the motion.
|
|
|
142
142
|
|
|
143
143
|
**2. A folder is a team if it contains `team.yaml`.** Everything inside is a member, and a member is one of three things: a **worker** (an agent with a goal), a **team** (**[v0.3]** a subfolder with its own `team.yaml` — just another node in its parent's flow: *its turn means running its own internal flow to completion*, like a subcommittee: it deliberates on its own whiteboard, and the parent hears only its report — `report_from:` in its `team.yaml` says whose words those are), or a **toolkeeper** (the member who holds the keys to a tool). Complexity is contained by hierarchy, not by syntax. There is no registry file listing your agents; the file browser is the org chart.
|
|
144
144
|
|
|
145
|
-
|
|
145
|
+
The whole folder — team and toolkeepers — is a **package**: copy it anywhere and it gets the same job done. The work itself comes from outside: you hand the team a topic when you run it, or it uses the default written in `team.yaml`.
|
|
146
146
|
|
|
147
147
|
**3. Every team has a chair, and there are no hidden if-statements.** Someone always decides who acts next, and TeamRunner makes you say who:
|
|
148
148
|
|
|
@@ -152,45 +152,38 @@ Tools are not members. An organization doesn't hand every worker every tool; a f
|
|
|
152
152
|
|
|
153
153
|
Every routing decision is logged as an event attributed to whoever made it. Which means *protocol vs. discretion* — a script vs. a manager exercising judgment — is itself something you can A/B test by swapping one file for the other (**[v0.3]**).
|
|
154
154
|
|
|
155
|
-
**4.
|
|
155
|
+
**4. Tools sit with a toolkeeper.** Tools are not members. An organization doesn't hand every worker every tool; a factory has a tool crib, with someone at the window who checks who may take what, and everyone else asks there. So the only members who touch tools are toolkeepers — a toolkeeper holds the guardrails (timeouts, no network, which folders), decides by a plain access list rather than a prompt, and its text body is simply what the team is told about it. Who may use a toolkeeper, and on what terms, is up to the toolkeeper's own access list — one toolkeeper can give different members different terms, the way a library gives professors and students different cards.
|
|
156
156
|
|
|
157
|
-
|
|
158
|
-
|---|---|---|---|
|
|
159
|
-
| **The whiteboard** (`whiteboard.yaml`) | the meeting, and the official record | everyone, unless a `read_by` line says otherwise | per item `written_by`; whatever anyone says is posted automatically; always logged |
|
|
160
|
-
| **Memory** | what you were in the room for | you | nobody — history is append-only |
|
|
157
|
+
**5. Every run is kept, and no agent can touch the record.** Every run gets its own folder in `runs/` with every prompt, everything said, every decision about who acts next, every tool call, the model that answered, tokens, time and cost (see [What lands in a run folder](#what-lands-in-a-run-folder)). The run log is the researcher's camera, outside the simulation: **no agent can ever read or write it** — a hard guarantee, without which every study of who knows what leaks.
|
|
161
158
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
Information asymmetry is not a feature we had to invent; it is a narrow `read_by`. Incentives are numeric items on the whiteboard. Private briefs are items only one party can read.
|
|
165
|
-
|
|
166
|
-
And one thing that is emphatically *not* a layer: the run log. It is the researcher's camera, outside the simulation. **No agent can ever read or write it** — a hard guarantee, without which every asymmetry design leaks.
|
|
167
|
-
|
|
168
|
-
**5. Experiments are overlays.** **[v0.2]** Your package stays clean and runnable. An `experiment.yaml` lives *outside* it, names it with `base:`, and declares factors as *patches* against it, plus replications and a seed. Single runs and 200-run factorials go through the same engine. When a variant wins, `teamrunner promote` copies the exact version that ran back into the package — same agent, new version — and `export` hands you a standalone copy for production.
|
|
159
|
+
Two more ideas are designed but not built yet — a whiteboard for who sees what, and experiments as overlays — and are described in [PREVIEW.md](PREVIEW.md).
|
|
169
160
|
|
|
170
161
|
---
|
|
171
162
|
|
|
172
163
|
## Tutorial: your first debate in 10 minutes
|
|
173
164
|
|
|
174
|
-
We'll build a three-agent debate, run it, give it rounds, a fact checker and the web
|
|
165
|
+
We'll build a three-agent debate, run it, give it rounds, a fact checker and the web. Zero code throughout. Turning it into a 40-run experiment comes with 0.2: see [PREVIEW.md](PREVIEW.md#experiments-v02).
|
|
175
166
|
|
|
176
|
-
> Everything in this tutorial
|
|
167
|
+
> Everything in this tutorial works in the preview. See [Status](#status-and-roadmap).
|
|
177
168
|
|
|
178
169
|
### Step 0 — install
|
|
179
170
|
|
|
180
171
|
```bash
|
|
181
|
-
|
|
172
|
+
uv tool install teamrunner # uv fetches the right Python for you: https://docs.astral.sh/uv/
|
|
173
|
+
pip install teamrunner # or this, if you already have Python 3.10 or later
|
|
182
174
|
```
|
|
183
175
|
|
|
184
|
-
Put your
|
|
176
|
+
Put your key in TeamRunner's key file, `~/.teamrunner/.env` (in your home folder, outside every team). One key is enough: the one for the provider your team's model uses. This tutorial's team runs on OpenAI:
|
|
185
177
|
|
|
186
178
|
```
|
|
187
179
|
OPENAI_API_KEY=sk-...
|
|
188
|
-
ANTHROPIC_API_KEY=sk-ant-...
|
|
189
180
|
```
|
|
190
181
|
|
|
182
|
+
A team on another provider takes that provider's key instead (`ANTHROPIC_API_KEY`, `GEMINI_API_KEY`, …). The shipped examples run on OpenRouter, so they need only `OPENROUTER_API_KEY`. If a key is missing, the run stops before spending anything and says which one. You can try every step without a key: `teamrunner run --rehearse` runs the whole team with no model, for free.
|
|
183
|
+
|
|
191
184
|
Keys stay with you, never with your teams: team folders get copied, zipped and sent to people, and a key inside one goes with it. If you already have a key set in your shell, TeamRunner offers to save it to the key file the first time it needs it (or to use it just this once). If it finds a `.env` inside a team folder, it offers to move the key out and delete it there. And it will **refuse to run** if it finds something that looks like an API key inside a spec file.
|
|
192
185
|
|
|
193
|
-
Models on your own machine work too, free: install [Ollama](https://ollama.com), pull a model (`ollama pull
|
|
186
|
+
Models on your own machine work too, free: install [Ollama](https://ollama.com), pull a model (`ollama pull gpt-oss:20b`), and write `default_model: ollama/gpt-oss:20b` in `team.yaml`. If Ollama runs somewhere other than this computer, put its address in the key file as `OLLAMA_API_BASE`. Choose one of about 20 billion parameters or more: the smallest models often fail at exactly what teams need most — answering in a fixed form and asking toolkeepers properly — so they test the wiring better than they stand in for a real team. Before the first turn of every run, TeamRunner checks that each model your team names is available and lists every problem it finds in one table, so you never pay for half a run. `teamrunner validate --online` runs the same check without a run.
|
|
194
187
|
|
|
195
188
|
### Step 1 — make a team
|
|
196
189
|
|
|
@@ -208,12 +201,14 @@ Two other ways to start, when you'd rather not begin from nothing:
|
|
|
208
201
|
|
|
209
202
|
This tutorial starts from nothing, so you see every file.
|
|
210
203
|
|
|
211
|
-
`team.yaml` is the only required file. It marks the folder as a team
|
|
204
|
+
`team.yaml` is the only required file. It marks the folder as a team, says what the team does, and names the model its agents run on:
|
|
212
205
|
|
|
213
206
|
```yaml
|
|
214
207
|
# team.yaml
|
|
215
208
|
name: debate
|
|
216
209
|
description: Two debaters argue a topic; a judge decides
|
|
210
|
+
|
|
211
|
+
default_model: openai/gpt-6-luna
|
|
217
212
|
```
|
|
218
213
|
|
|
219
214
|
Two things worth knowing now:
|
|
@@ -229,7 +224,6 @@ An agent file is Markdown. Frontmatter configures, body prompts.
|
|
|
229
224
|
<!-- advocate.md -->
|
|
230
225
|
---
|
|
231
226
|
description: Argues in favor of the topic
|
|
232
|
-
model: openai/gpt-6-luna
|
|
233
227
|
---
|
|
234
228
|
You are debating in favor of this topic:
|
|
235
229
|
|
|
@@ -244,7 +238,6 @@ recent point before adding your own. Be persuasive but honest.
|
|
|
244
238
|
<!-- critic.md -->
|
|
245
239
|
---
|
|
246
240
|
description: Argues against the topic
|
|
247
|
-
model: openai/gpt-6-luna
|
|
248
241
|
---
|
|
249
242
|
You are debating against this topic:
|
|
250
243
|
|
|
@@ -259,7 +252,6 @@ Be persuasive but honest.
|
|
|
259
252
|
<!-- judge.md -->
|
|
260
253
|
---
|
|
261
254
|
description: Decides who argued better
|
|
262
|
-
model: openai/gpt-6-luna
|
|
263
255
|
output:
|
|
264
256
|
winner: [advocate, critic]
|
|
265
257
|
reasoning: ""
|
|
@@ -275,7 +267,7 @@ explain your decision in one paragraph.
|
|
|
275
267
|
|
|
276
268
|
Four things just happened:
|
|
277
269
|
|
|
278
|
-
**
|
|
270
|
+
**The team names the model once.** No agent above names a model, so all three run on `default_model:` from `team.yaml`. An agent that should run on a different one says so itself (`model: anthropic/…`), and its own line wins. A model with its settings can live in a profile, `models/careful.yaml`, named as `default_model: careful.yaml` or `model: careful.yaml`. `teamrunner show judge` prints exactly which model and settings the judge will run with, and where each came from. `examples/orchestrators_lite` does both: its five engineers share one profile, `models/engineer.yaml`, named once as the team's `default_model:`. Models churn, so either line can name backups in order of preference, separated by commas: `default_model: openai/gpt-6-luna, anthropic/claude-sonnet-4-5`. Before the first turn TeamRunner picks the first one available, keeps it for the whole run, and says so whenever it isn't the first (`↪ judge runs on anthropic/claude-sonnet-4-5, its 2nd choice — …`); the run's record says so too.
|
|
279
271
|
|
|
280
272
|
**Alphabetical order is the flow.** With no `chair.md`, members act in alphabetical filename order, one turn each — here `advocate → critic → judge`. That is also why the files above have no `name:` line: an agent's name is its filename. The folder listing *is* the running order, visible in any file browser. Rename to reorder.
|
|
281
273
|
|
|
@@ -382,7 +374,6 @@ Suppose we want each speech fact-checked before it stands. Write a fact checker
|
|
|
382
374
|
<!-- fact_checker.md -->
|
|
383
375
|
---
|
|
384
376
|
description: Checks the factual claims in the latest speech
|
|
385
|
-
model: openai/gpt-6-luna
|
|
386
377
|
output:
|
|
387
378
|
verdict: [pass, fail]
|
|
388
379
|
reasons: ""
|
|
@@ -470,111 +461,6 @@ A toolkeeper step means the member just before it must end its turn with a reque
|
|
|
470
461
|
|
|
471
462
|
TeamRunner 0.1 has four built-in tools: `web_search_brave` (Brave Search), `read_page` (a link in, the page's text out), `read_file` (a file the run was given with `--file`, its text out) and `run_code` (Python in a sandbox: no internet unless the toolkeeper allows it, and files written only in the run's own work folder). The sandbox is Python running in WebAssembly, and it installs with TeamRunner — nothing else to set up; it can use packages built for it (numpy, pandas, scipy, sympy and many more), but not every package. `examples/fact_checked` gives the fact checker a second toolkeeper, `sandbox.md`, so it can check the sums in a claim by running them. A toolkeeper holds one tool in 0.1, so its limits always mean one thing; a member who needs two tools asks two toolkeepers, as the fact checker does here. `examples/reference_check` uses `read_page` and `read_file`: it checks every reference in a paper.
|
|
472
463
|
|
|
473
|
-
### Step 8 — private information and shared records **[v0.3]**
|
|
474
|
-
|
|
475
|
-
The debate doesn't need this, but the moment you study organizations you will. `whiteboard.yaml` is the team's whiteboard: declared, typed items, each with who may read and write it. Everything anyone says is posted there too, open to all unless a `read_by` line says otherwise.
|
|
476
|
-
|
|
477
|
-
```yaml
|
|
478
|
-
# whiteboard.yaml
|
|
479
|
-
|
|
480
|
-
# Bare list = a choice, starting at the first option.
|
|
481
|
-
# Read by everyone, written by the chair — those are the defaults.
|
|
482
|
-
stage: [opening, rebuttal, counter, closing, done]
|
|
483
|
-
|
|
484
|
-
# A bare value = a starting value, read and written by the defaults.
|
|
485
|
-
rounds_left: 3
|
|
486
|
-
|
|
487
|
-
# Spell it out only when you change who reads or writes it.
|
|
488
|
-
score:
|
|
489
|
-
starts_as: 0
|
|
490
|
-
written_by: [judge]
|
|
491
|
-
|
|
492
|
-
# Information asymmetry IS a read permission.
|
|
493
|
-
buyer_ceiling:
|
|
494
|
-
starts_as: 850
|
|
495
|
-
read_by: [buyer]
|
|
496
|
-
```
|
|
497
|
-
|
|
498
|
-
Every field is declared up front — no ad-hoc keys appearing mid-run. Every write is harness-mediated and logged as a `state_write` event: an agent listed in `written_by` returns the new value as a declared output field; nothing pokes state directly. Agents reference readable fields in their prompts as `{{whiteboard.buyer_ceiling}}`, and the validator checks that permission before you spend a cent.
|
|
499
|
-
|
|
500
|
-
This one file is doing a surprising amount of work. Private valuations, confidential negotiating briefs, payoffs and incentives, task inputs, an artifact handed from one department to the next — all of them are just whiteboard items with the right permissions.
|
|
501
|
-
|
|
502
|
-
---
|
|
503
|
-
|
|
504
|
-
## Tutorial part 2: your first experiment **[v0.2]**
|
|
505
|
-
|
|
506
|
-
Here's the question that motivated the whole project: **does it matter which model plays the advocate?**
|
|
507
|
-
|
|
508
|
-
Don't touch the debate. Make a folder next to it with one file:
|
|
509
|
-
|
|
510
|
-
> **[v0.2]** Experiments are built after the package is right. The file below is the agreed shape: it lives *outside* the package (`experiments/advocate_model/experiment.yaml`) and names it with `base:`.
|
|
511
|
-
|
|
512
|
-
```yaml
|
|
513
|
-
# experiments/advocate_model/experiment.yaml
|
|
514
|
-
name: advocate-model-ab
|
|
515
|
-
base: ../../debate
|
|
516
|
-
task: tasks/remote_work
|
|
517
|
-
|
|
518
|
-
factors:
|
|
519
|
-
advocate_model:
|
|
520
|
-
- label: gpt
|
|
521
|
-
patch: {advocate.model: "openai/gpt-6-luna"}
|
|
522
|
-
- label: claude
|
|
523
|
-
patch: {advocate.model: "anthropic/claude-sonnet-4-5"}
|
|
524
|
-
|
|
525
|
-
replications: 20 # 2 conditions × 20 = 40 runs
|
|
526
|
-
seed: 42
|
|
527
|
-
|
|
528
|
-
limits:
|
|
529
|
-
max_concurrent: 4
|
|
530
|
-
max_cost_usd: 40.00
|
|
531
|
-
```
|
|
532
|
-
|
|
533
|
-
```bash
|
|
534
|
-
teamrunner experiment .
|
|
535
|
-
```
|
|
536
|
-
|
|
537
|
-
What just became possible:
|
|
538
|
-
|
|
539
|
-
**Factors are patches, so the base spec stays clean.** `advocate.model` means "the `model` field of the component `advocate`". Patch paths address any field of any component, including the prompt body (the field is called `prompt`), and any value can be `file:<path>` to swap in a whole file. `patch: {}` is the *unmodified base spec* — the control condition, written honestly as a level rather than smuggled in as "the normal run."
|
|
540
|
-
|
|
541
|
-
**Anything in a file is a factor.** That's not a slogan, it's the mechanism. A few real examples from our worked recasts:
|
|
542
|
-
|
|
543
|
-
```yaml
|
|
544
|
-
# A prompt/strategy A/B — same agent, two personalities
|
|
545
|
-
- {label: tough, patch: {buyer.prompt: file:variants/buyer_tough.md}}
|
|
546
|
-
|
|
547
|
-
# A treatment: one member is secretly self-interested
|
|
548
|
-
- {label: saboteur, patch: {council.prompt: file:variants/saboteur.md}}
|
|
549
|
-
|
|
550
|
-
# The communication structure ITSELF as the factor:
|
|
551
|
-
# same reviewers, same paper — only who can read whose review changes
|
|
552
|
-
- label: public
|
|
553
|
-
patch:
|
|
554
|
-
whiteboard.said.reviewer_1.read_by: everyone
|
|
555
|
-
whiteboard.said.reviewer_2.read_by: everyone
|
|
556
|
-
whiteboard.said.reviewer_3.read_by: everyone
|
|
557
|
-
```
|
|
558
|
-
|
|
559
|
-
That last one is the founding claim of the product. Studying whether peer reviewers herd when they can see each other's reviews is, in TeamRunner, a two-level factor on who may read what each reviewer says.
|
|
560
|
-
|
|
561
|
-
**`replications` has a minimum of 2.** Writing `replications: 1` requires an explicit `allow_single_run: true`. LLMs are stochastic; single runs are anecdotes; we made the anecdote the awkward thing to write.
|
|
562
|
-
|
|
563
|
-
**One master `seed` fixes everything the harness controls** — condition assignment, ordering, per-run seed derivation. It does not, and cannot, make the model deterministic. See [Why we built it](#3-almost-nothing-published-about-multi-agent-systems-is-reproducible).
|
|
564
|
-
|
|
565
|
-
**`limits` is a real budget ceiling.** `max_cost_usd` stops the experiment; `max_concurrent` keeps you inside your rate limits.
|
|
566
|
-
|
|
567
|
-
Then get the data out:
|
|
568
|
-
|
|
569
|
-
```bash
|
|
570
|
-
teamrunner runs # browse what you've run
|
|
571
|
-
teamrunner export --experiment advocate-model-ab --format csv
|
|
572
|
-
```
|
|
573
|
-
|
|
574
|
-
Long format, one row per observation, straight into R, Stata, or pandas. Your analysis never lives inside our dashboard — that's a promise, not an oversight.
|
|
575
|
-
|
|
576
|
-
The declarative metrics layer (ground truth, LLM-as-judge with a separately pinned judge model, cost and time) is specified but its file format is still open. Today's `metrics:` references in the examples are placeholders.
|
|
577
|
-
|
|
578
464
|
---
|
|
579
465
|
|
|
580
466
|
## What lands in a run folder
|
|
@@ -634,7 +520,17 @@ replays that exact spec. Every run folder is a self-contained replication packag
|
|
|
634
520
|
|
|
635
521
|
## Going further: the worked examples
|
|
636
522
|
|
|
637
|
-
Six examples ship with TeamRunner, in `examples/`, simplest first — each adds something the one before it doesn't have. Copy one by name to start from it: `teamrunner new my_team --from orchestrators_lite`. Most are published multi-agent papers or projects, recast as TeamRunner files.
|
|
523
|
+
Six examples ship with TeamRunner, in `examples/`, simplest first — each adds something the one before it doesn't have. Copy one by name to start from it: `teamrunner new my_team --from orchestrators_lite`. Most are published multi-agent papers or projects, recast as TeamRunner files. All six use `openrouter/google/gemma-4-31b-it` and need only an OpenRouter API key, with credits for model usage. They do not require OpenAI, Anthropic, Brave or catalogue keys.
|
|
524
|
+
|
|
525
|
+
Set the key outside the team folder (never commit it):
|
|
526
|
+
|
|
527
|
+
```bash
|
|
528
|
+
export OPENROUTER_API_KEY="your-openrouter-key"
|
|
529
|
+
teamrunner new my_debate --from round_robin
|
|
530
|
+
teamrunner run my_debate
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
On PowerShell, set `$env:OPENROUTER_API_KEY="your-openrouter-key"` instead. You can also keep `OPENROUTER_API_KEY` in `~/.teamrunner/.env`. Add `--rehearse` to check a flow without calling a model; a rehearsal does not verify live model or tool behavior. The two source-checking examples read public pages and Crossref without extra keys; access restrictions, rate limits and missing abstracts or PDFs can still limit their evidence. The fact checker's Python sandbox downloads its runtime on first use. The code-review example uses demo model settings rather than the source paper's model.
|
|
638
534
|
|
|
639
535
|
| Example | Recast of | What it adds |
|
|
640
536
|
|---|---|---|
|
|
@@ -642,7 +538,7 @@ Six examples ship with TeamRunner, in `examples/`, simplest first — each adds
|
|
|
642
538
|
| **`multi_agent_debate/`** | muthuspark/multi-agent-debate | A chair: the debate as a script, with a repeated block of rounds. |
|
|
643
539
|
| **`hiring_committee/`** | Stasser & Titus 1985 (hidden profile) | A committee picks a candidate when the key facts are spread across its members: facts only one member knows, kept in that member's own file; a stage in the chair; a clerk who records the decision; and both meeting formats in one `chair.md`, one commented out. |
|
|
644
540
|
| **`orchestrators_lite/`** | Fukui 2026 (lite) | Five engineers review code against planted bugs: a model profile the whole team shares, and two inputs. |
|
|
645
|
-
| **`fact_checked/`** | — | The debate with a fact checker: decisions that send a speech back, counted tries, and toolkeepers — a
|
|
541
|
+
| **`fact_checked/`** | — | The debate with a fact checker: decisions that send a speech back, counted tries, and toolkeepers — a public-source reader with different terms for different members, a required source-reading step, and a Python sandbox. |
|
|
646
542
|
| **`reference_check/`** | sciwrite-lint (Samsonau 2026) | Checks every reference in a paper: that it exists, that its details are right, and that the cited paper says what the citing sentence claims. A paper given as a link or a file (`--file`), toolkeepers holding `read_page` and `read_file`, the same tool under two toolkeepers with different `domains`, a decision that can stop the run, and batches of ten as a loop with a counted exit. |
|
|
647
543
|
|
|
648
544
|
**Coming with 0.3**, recast on paper and waiting for the features they need: **Deb8flow** (subteams — each side a debater plus its own fact checker), **NegotiationGym** (private valuations, a loop either side can end), **LLM-Deliberation** (four parties, confidential briefs, one secretly given a hidden agenda), **AgentReview** (three reviewers at once, sealed reviews — do reviewers herd when reviews are public?), **ChatDev** (a three-level company, each department on its own whiteboard), and the full **Invisible Orchestrators** study (a hidden orchestrator whose words reach the team only as unsigned "policy updates").
|
|
@@ -665,7 +561,7 @@ The recasting campaign is the point, not decoration: each one is run *before* th
|
|
|
665
561
|
|
|
666
562
|
## Status and roadmap
|
|
667
563
|
|
|
668
|
-
**Preview.** What the roadmap calls 0.1 is out as a soft launch, numbered 0.0.x: every command in the tutorial not
|
|
564
|
+
**Preview.** What the roadmap calls 0.1 is out as a soft launch, numbered 0.0.x: every command in the tutorial works; what is designed but not built yet is in [PREVIEW.md](PREVIEW.md). It may still change in ways that break earlier teams and runs until 0.1.0 is announced. What changed in each version is in the [changelog](https://github.com/teamrunner/teamrunner/blob/main/CHANGELOG.md).
|
|
669
565
|
|
|
670
566
|
| Version | |
|
|
671
567
|
|---|---|
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# What's coming
|
|
2
|
+
|
|
3
|
+
Designed, not built yet. **Nothing on this page runs in the current preview, and none of it is in the tutorial.** The shapes below are agreed, but details may change before they ship. What works today is in the [README](README.md); the order things arrive in is under [Status and roadmap](README.md#status-and-roadmap).
|
|
4
|
+
|
|
5
|
+
- [Who sees what: the whiteboard](#who-sees-what-the-whiteboard-v03) **[v0.3]**
|
|
6
|
+
- [Experiments](#experiments-v02) **[v0.2]**
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Who sees what: the whiteboard **[v0.3]**
|
|
11
|
+
|
|
12
|
+
Everything an agent knows arrives through one of:
|
|
13
|
+
|
|
14
|
+
| Layer | Org analogue | Who reads | Who writes |
|
|
15
|
+
|---|---|---|---|
|
|
16
|
+
| **The whiteboard** (`whiteboard.yaml`) | the meeting, and the official record | everyone, unless a `read_by` line says otherwise | per item `written_by`; whatever anyone says is posted automatically; always logged |
|
|
17
|
+
| **Memory** | what you were in the room for | you | nobody — history is append-only |
|
|
18
|
+
|
|
19
|
+
Everything said is posted on the whiteboard, open to all by default, so a team with no whiteboard file is a meeting room — and that is all of v0.1. **[v0.3]** `whiteboard.yaml` adds the rest: seal the reviewers from each other, or make the team a relay where each person hears only who spoke before them, with a `read_by` line for what was said — one line each.
|
|
20
|
+
|
|
21
|
+
Information asymmetry is not a feature we had to invent; it is a narrow `read_by`. Incentives are numeric items on the whiteboard. Private briefs are items only one party can read.
|
|
22
|
+
|
|
23
|
+
### An example
|
|
24
|
+
|
|
25
|
+
The debate doesn't need this, but the moment you study organizations you will. `whiteboard.yaml` is the team's whiteboard: declared, typed items, each with who may read and write it. Everything anyone says is posted there too, open to all unless a `read_by` line says otherwise.
|
|
26
|
+
|
|
27
|
+
```yaml
|
|
28
|
+
# whiteboard.yaml
|
|
29
|
+
|
|
30
|
+
# Bare list = a choice, starting at the first option.
|
|
31
|
+
# Read by everyone, written by the chair — those are the defaults.
|
|
32
|
+
stage: [opening, rebuttal, counter, closing, done]
|
|
33
|
+
|
|
34
|
+
# A bare value = a starting value, read and written by the defaults.
|
|
35
|
+
rounds_left: 3
|
|
36
|
+
|
|
37
|
+
# Spell it out only when you change who reads or writes it.
|
|
38
|
+
score:
|
|
39
|
+
starts_as: 0
|
|
40
|
+
written_by: [judge]
|
|
41
|
+
|
|
42
|
+
# Information asymmetry IS a read permission.
|
|
43
|
+
buyer_ceiling:
|
|
44
|
+
starts_as: 850
|
|
45
|
+
read_by: [buyer]
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Every field is declared up front — no ad-hoc keys appearing mid-run. Every write is harness-mediated and logged as a `state_write` event: an agent listed in `written_by` returns the new value as a declared output field; nothing pokes state directly. Agents reference readable fields in their prompts as `{{whiteboard.buyer_ceiling}}`, and the validator checks that permission before you spend a cent.
|
|
49
|
+
|
|
50
|
+
This one file is doing a surprising amount of work. Private valuations, confidential negotiating briefs, payoffs and incentives, task inputs, an artifact handed from one department to the next — all of them are just whiteboard items with the right permissions.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Experiments **[v0.2]**
|
|
55
|
+
|
|
56
|
+
Your package stays clean and runnable. An `experiment.yaml` lives *outside* it, names it with `base:`, and declares factors as *patches* against it, plus replications and a seed. Single runs and 200-run factorials go through the same engine. When a variant wins, `teamrunner promote` copies the exact version that ran back into the package — same agent, new version — and `export` hands you a standalone copy for production.
|
|
57
|
+
|
|
58
|
+
### Your first experiment
|
|
59
|
+
|
|
60
|
+
Here's the question that motivated the whole project: **does it matter which model plays the advocate?**
|
|
61
|
+
|
|
62
|
+
Don't touch the debate. Make a folder next to it with one file:
|
|
63
|
+
|
|
64
|
+
```yaml
|
|
65
|
+
# experiments/advocate_model/experiment.yaml
|
|
66
|
+
name: advocate-model-ab
|
|
67
|
+
base: ../../debate
|
|
68
|
+
task: tasks/remote_work
|
|
69
|
+
|
|
70
|
+
factors:
|
|
71
|
+
advocate_model:
|
|
72
|
+
- label: gpt
|
|
73
|
+
patch: {advocate.model: "openai/gpt-6-luna"}
|
|
74
|
+
- label: claude
|
|
75
|
+
patch: {advocate.model: "anthropic/claude-sonnet-4-5"}
|
|
76
|
+
|
|
77
|
+
replications: 20 # 2 conditions × 20 = 40 runs
|
|
78
|
+
seed: 42
|
|
79
|
+
|
|
80
|
+
limits:
|
|
81
|
+
max_concurrent: 4
|
|
82
|
+
max_cost_usd: 40.00
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
teamrunner experiment .
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
What just became possible:
|
|
90
|
+
|
|
91
|
+
**Factors are patches, so the base spec stays clean.** `advocate.model` means "the `model` field of the component `advocate`". Patch paths address any field of any component, including the prompt body (the field is called `prompt`), and any value can be `file:<path>` to swap in a whole file. `patch: {}` is the *unmodified base spec* — the control condition, written honestly as a level rather than smuggled in as "the normal run."
|
|
92
|
+
|
|
93
|
+
**Anything in a file is a factor.** That's not a slogan, it's the mechanism. A few real examples from our worked recasts:
|
|
94
|
+
|
|
95
|
+
```yaml
|
|
96
|
+
# A prompt/strategy A/B — same agent, two personalities
|
|
97
|
+
- {label: tough, patch: {buyer.prompt: file:variants/buyer_tough.md}}
|
|
98
|
+
|
|
99
|
+
# A treatment: one member is secretly self-interested
|
|
100
|
+
- {label: saboteur, patch: {council.prompt: file:variants/saboteur.md}}
|
|
101
|
+
|
|
102
|
+
# The communication structure ITSELF as the factor:
|
|
103
|
+
# same reviewers, same paper — only who can read whose review changes
|
|
104
|
+
- label: public
|
|
105
|
+
patch:
|
|
106
|
+
whiteboard.said.reviewer_1.read_by: everyone
|
|
107
|
+
whiteboard.said.reviewer_2.read_by: everyone
|
|
108
|
+
whiteboard.said.reviewer_3.read_by: everyone
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
That last one is the founding claim of the product. Studying whether peer reviewers herd when they can see each other's reviews is, in TeamRunner, a two-level factor on who may read what each reviewer says.
|
|
112
|
+
|
|
113
|
+
**`replications` has a minimum of 2.** Writing `replications: 1` requires an explicit `allow_single_run: true`. LLMs are stochastic; single runs are anecdotes; we made the anecdote the awkward thing to write.
|
|
114
|
+
|
|
115
|
+
**One master `seed` fixes everything the harness controls** — condition assignment, ordering, per-run seed derivation. It does not, and cannot, make the model deterministic. See [Why we built it](README.md#3-almost-nothing-published-about-multi-agent-systems-is-reproducible).
|
|
116
|
+
|
|
117
|
+
**`limits` is a real budget ceiling.** `max_cost_usd` stops the experiment; `max_concurrent` keeps you inside your rate limits.
|
|
118
|
+
|
|
119
|
+
Then get the data out:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
teamrunner runs # browse what you've run
|
|
123
|
+
teamrunner export --experiment advocate-model-ab --format csv
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Long format, one row per observation, straight into R, Stata, or pandas. Your analysis never lives inside our dashboard — that's a promise, not an oversight.
|
|
127
|
+
|
|
128
|
+
The declarative metrics layer (ground truth, LLM-as-judge with a separately pinned judge model, cost and time) is specified but its file format is still open. Today's `metrics:` references in the examples are placeholders.
|