amness 0.0.0-stage → 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.
Files changed (233) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +212 -2
  3. package/dist/cli/acpcli.d.ts +7 -0
  4. package/dist/cli/acpcli.js +14 -0
  5. package/dist/cli/amness.d.ts +2 -0
  6. package/dist/cli/amness.js +693 -0
  7. package/dist/cli/benchcli.d.ts +5 -0
  8. package/dist/cli/benchcli.js +160 -0
  9. package/dist/cli/config.d.ts +79 -0
  10. package/dist/cli/config.js +54 -0
  11. package/dist/cli/demo.d.ts +13 -0
  12. package/dist/cli/demo.js +44 -0
  13. package/dist/cli/detect.d.ts +2 -0
  14. package/dist/cli/detect.js +20 -0
  15. package/dist/cli/evalcli.d.ts +15 -0
  16. package/dist/cli/evalcli.js +198 -0
  17. package/dist/cli/format.d.ts +5 -0
  18. package/dist/cli/format.js +55 -0
  19. package/dist/cli/headless.d.ts +2 -0
  20. package/dist/cli/headless.js +169 -0
  21. package/dist/cli/model.d.ts +11 -0
  22. package/dist/cli/model.js +19 -0
  23. package/dist/cli/plugincli.d.ts +2 -0
  24. package/dist/cli/plugincli.js +176 -0
  25. package/dist/cli/schedulecli.d.ts +2 -0
  26. package/dist/cli/schedulecli.js +66 -0
  27. package/dist/cli/state.d.ts +11 -0
  28. package/dist/cli/state.js +19 -0
  29. package/dist/cli/tui/ansi.d.ts +38 -0
  30. package/dist/cli/tui/ansi.js +142 -0
  31. package/dist/cli/tui/app.d.ts +328 -0
  32. package/dist/cli/tui/app.js +1358 -0
  33. package/dist/cli/tui/blocks.d.ts +151 -0
  34. package/dist/cli/tui/blocks.js +128 -0
  35. package/dist/cli/tui/brand.d.ts +9 -0
  36. package/dist/cli/tui/brand.js +16 -0
  37. package/dist/cli/tui/canvas.d.ts +92 -0
  38. package/dist/cli/tui/canvas.js +199 -0
  39. package/dist/cli/tui/cards.d.ts +44 -0
  40. package/dist/cli/tui/cards.js +215 -0
  41. package/dist/cli/tui/clipboard.d.ts +5 -0
  42. package/dist/cli/tui/clipboard.js +29 -0
  43. package/dist/cli/tui/commands.d.ts +10 -0
  44. package/dist/cli/tui/commands.js +649 -0
  45. package/dist/cli/tui/complete.d.ts +39 -0
  46. package/dist/cli/tui/complete.js +113 -0
  47. package/dist/cli/tui/custom.d.ts +9 -0
  48. package/dist/cli/tui/custom.js +34 -0
  49. package/dist/cli/tui/diffview.d.ts +25 -0
  50. package/dist/cli/tui/diffview.js +130 -0
  51. package/dist/cli/tui/editor.d.ts +60 -0
  52. package/dist/cli/tui/editor.js +230 -0
  53. package/dist/cli/tui/full.d.ts +86 -0
  54. package/dist/cli/tui/full.js +630 -0
  55. package/dist/cli/tui/keys.d.ts +31 -0
  56. package/dist/cli/tui/keys.js +134 -0
  57. package/dist/cli/tui/markdown.d.ts +37 -0
  58. package/dist/cli/tui/markdown.js +155 -0
  59. package/dist/cli/tui/mentions.d.ts +15 -0
  60. package/dist/cli/tui/mentions.js +48 -0
  61. package/dist/cli/tui/modal.d.ts +26 -0
  62. package/dist/cli/tui/modal.js +107 -0
  63. package/dist/cli/tui/overlays.d.ts +98 -0
  64. package/dist/cli/tui/overlays.js +237 -0
  65. package/dist/cli/tui/pager.d.ts +15 -0
  66. package/dist/cli/tui/pager.js +66 -0
  67. package/dist/cli/tui/pricing.d.ts +9 -0
  68. package/dist/cli/tui/pricing.js +23 -0
  69. package/dist/cli/tui/rich.d.ts +16 -0
  70. package/dist/cli/tui/rich.js +72 -0
  71. package/dist/cli/tui/screen.d.ts +30 -0
  72. package/dist/cli/tui/screen.js +62 -0
  73. package/dist/cli/tui/session.d.ts +77 -0
  74. package/dist/cli/tui/session.js +103 -0
  75. package/dist/cli/tui/sidebar.d.ts +84 -0
  76. package/dist/cli/tui/sidebar.js +114 -0
  77. package/dist/cli/tui/text.d.ts +15 -0
  78. package/dist/cli/tui/text.js +94 -0
  79. package/dist/cli/tui/theme.d.ts +59 -0
  80. package/dist/cli/tui/theme.js +148 -0
  81. package/dist/cli/tui/themes.d.ts +56 -0
  82. package/dist/cli/tui/themes.js +80 -0
  83. package/dist/cli/tui/tokens.d.ts +39 -0
  84. package/dist/cli/tui/tokens.js +71 -0
  85. package/dist/cli/tui/view.d.ts +60 -0
  86. package/dist/cli/tui/view.js +178 -0
  87. package/dist/cli/ui.d.ts +34 -0
  88. package/dist/cli/ui.js +224 -0
  89. package/dist/src/acp.d.ts +28 -0
  90. package/dist/src/acp.js +111 -0
  91. package/dist/src/agents.d.ts +23 -0
  92. package/dist/src/agents.js +71 -0
  93. package/dist/src/anthropic.d.ts +30 -0
  94. package/dist/src/anthropic.js +91 -0
  95. package/dist/src/approver.d.ts +15 -0
  96. package/dist/src/approver.js +40 -0
  97. package/dist/src/bench.d.ts +67 -0
  98. package/dist/src/bench.js +201 -0
  99. package/dist/src/bundle.d.ts +36 -0
  100. package/dist/src/bundle.js +55 -0
  101. package/dist/src/chaos.d.ts +15 -0
  102. package/dist/src/chaos.js +26 -0
  103. package/dist/src/code.d.ts +187 -0
  104. package/dist/src/code.js +590 -0
  105. package/dist/src/codeindex.d.ts +65 -0
  106. package/dist/src/codeindex.js +300 -0
  107. package/dist/src/deep.d.ts +62 -0
  108. package/dist/src/deep.js +177 -0
  109. package/dist/src/diff.d.ts +8 -0
  110. package/dist/src/diff.js +74 -0
  111. package/dist/src/dynamic.d.ts +42 -0
  112. package/dist/src/dynamic.js +133 -0
  113. package/dist/src/embed.d.ts +8 -0
  114. package/dist/src/embed.js +25 -0
  115. package/dist/src/evalcases.d.ts +11 -0
  116. package/dist/src/evalcases.js +196 -0
  117. package/dist/src/evals.d.ts +197 -0
  118. package/dist/src/evals.js +340 -0
  119. package/dist/src/gitflow.d.ts +27 -0
  120. package/dist/src/gitflow.js +56 -0
  121. package/dist/src/grade.d.ts +42 -0
  122. package/dist/src/grade.js +96 -0
  123. package/dist/src/guidance.d.ts +15 -0
  124. package/dist/src/guidance.js +68 -0
  125. package/dist/src/hardcases.d.ts +2 -0
  126. package/dist/src/hardcases.js +94 -0
  127. package/dist/src/harness.d.ts +411 -0
  128. package/dist/src/harness.js +725 -0
  129. package/dist/src/hooks.d.ts +44 -0
  130. package/dist/src/hooks.js +116 -0
  131. package/dist/src/images.d.ts +13 -0
  132. package/dist/src/images.js +27 -0
  133. package/dist/src/index.d.ts +57 -0
  134. package/dist/src/index.js +57 -0
  135. package/dist/src/ledger.d.ts +58 -0
  136. package/dist/src/ledger.js +78 -0
  137. package/dist/src/live.d.ts +16 -0
  138. package/dist/src/live.js +80 -0
  139. package/dist/src/lsp.d.ts +31 -0
  140. package/dist/src/lsp.js +147 -0
  141. package/dist/src/memory.d.ts +128 -0
  142. package/dist/src/memory.js +390 -0
  143. package/dist/src/metrics.d.ts +3 -0
  144. package/dist/src/metrics.js +42 -0
  145. package/dist/src/mining.d.ts +49 -0
  146. package/dist/src/mining.js +126 -0
  147. package/dist/src/openai.d.ts +50 -0
  148. package/dist/src/openai.js +307 -0
  149. package/dist/src/parallel.d.ts +66 -0
  150. package/dist/src/parallel.js +135 -0
  151. package/dist/src/patch.d.ts +45 -0
  152. package/dist/src/patch.js +219 -0
  153. package/dist/src/permissions.d.ts +46 -0
  154. package/dist/src/permissions.js +245 -0
  155. package/dist/src/plugins.d.ts +148 -0
  156. package/dist/src/plugins.js +225 -0
  157. package/dist/src/pluginscan.d.ts +8 -0
  158. package/dist/src/pluginscan.js +20 -0
  159. package/dist/src/procs.d.ts +41 -0
  160. package/dist/src/procs.js +94 -0
  161. package/dist/src/profiles.d.ts +36 -0
  162. package/dist/src/profiles.js +61 -0
  163. package/dist/src/progress.d.ts +29 -0
  164. package/dist/src/progress.js +75 -0
  165. package/dist/src/prompts.d.ts +10 -0
  166. package/dist/src/prompts.js +28 -0
  167. package/dist/src/ratelimit.d.ts +34 -0
  168. package/dist/src/ratelimit.js +116 -0
  169. package/dist/src/replay.d.ts +25 -0
  170. package/dist/src/replay.js +99 -0
  171. package/dist/src/review.d.ts +20 -0
  172. package/dist/src/review.js +49 -0
  173. package/dist/src/route.d.ts +9 -0
  174. package/dist/src/route.js +30 -0
  175. package/dist/src/router.d.ts +61 -0
  176. package/dist/src/router.js +126 -0
  177. package/dist/src/sandbox.d.ts +13 -0
  178. package/dist/src/sandbox.js +68 -0
  179. package/dist/src/schedule.d.ts +20 -0
  180. package/dist/src/schedule.js +59 -0
  181. package/dist/src/schema.d.ts +13 -0
  182. package/dist/src/schema.js +36 -0
  183. package/dist/src/secrets.d.ts +10 -0
  184. package/dist/src/secrets.js +41 -0
  185. package/dist/src/shell.d.ts +34 -0
  186. package/dist/src/shell.js +95 -0
  187. package/dist/src/skills.d.ts +20 -0
  188. package/dist/src/skills.js +112 -0
  189. package/dist/src/snapshot.d.ts +20 -0
  190. package/dist/src/snapshot.js +93 -0
  191. package/dist/src/stats.d.ts +24 -0
  192. package/dist/src/stats.js +62 -0
  193. package/dist/src/strategies.d.ts +16 -0
  194. package/dist/src/strategies.js +35 -0
  195. package/dist/src/suites.d.ts +30 -0
  196. package/dist/src/suites.js +112 -0
  197. package/dist/src/trace.d.ts +63 -0
  198. package/dist/src/trace.js +153 -0
  199. package/dist/src/tune.d.ts +38 -0
  200. package/dist/src/tune.js +49 -0
  201. package/dist/src/web.d.ts +19 -0
  202. package/dist/src/web.js +56 -0
  203. package/dist/src/worktree.d.ts +24 -0
  204. package/dist/src/worktree.js +85 -0
  205. package/docs/agent-loop.md +222 -0
  206. package/docs/architecture.md +228 -0
  207. package/docs/bench.md +293 -0
  208. package/docs/budgets.md +185 -0
  209. package/docs/build-your-own-harness.md +424 -0
  210. package/docs/cookbook.md +375 -0
  211. package/docs/development.md +150 -0
  212. package/docs/evaluation.md +450 -0
  213. package/docs/features.md +1320 -0
  214. package/docs/getting-started.md +196 -0
  215. package/docs/headless.md +183 -0
  216. package/docs/images/approval.png +0 -0
  217. package/docs/images/chat.png +0 -0
  218. package/docs/images/daylight.png +0 -0
  219. package/docs/images/loop.png +0 -0
  220. package/docs/images/palette.png +0 -0
  221. package/docs/images/running.png +0 -0
  222. package/docs/images/subagent-done.png +0 -0
  223. package/docs/images/subagent-running.png +0 -0
  224. package/docs/images/welcome.png +0 -0
  225. package/docs/index.md +25 -0
  226. package/docs/library.md +276 -0
  227. package/docs/plugins.md +691 -0
  228. package/docs/providers.md +175 -0
  229. package/docs/safety.md +237 -0
  230. package/docs/usage.md +348 -0
  231. package/docs/why.md +155 -0
  232. package/docs/writing-guide.md +39 -0
  233. package/package.json +72 -4
@@ -0,0 +1,450 @@
1
+ # Evaluating the harness
2
+
3
+ `amness eval` runs the coding agent on a set of tasks, with and without each safety feature, and tells you in numbers whether a change helped.
4
+
5
+ In this page you will learn:
6
+
7
+ - what an eval is, and why it needs many tasks and several trials
8
+ - how to run the built-in task suites and read the report
9
+ - how to write your own tasks and compare your own harness variants
10
+ - what has been measured so far, and what has not
11
+
12
+ ## What an eval is
13
+
14
+ An *eval* is a test for the agent. You give the agent a task in a fresh folder. When the agent stops, a separate check decides if the task is solved. The check is a shell command (exit code 0 means pass) or a function. The agent never sees the check. We call it the *held-out check*.
15
+
16
+ A *variant* is one way to set up the harness. For example, `baseline` has no guards and `full` has all guards. A *guard* is a rule in the agent loop that stops a known mistake, such as repeating the same call.
17
+
18
+ Each task runs in a new temporary workspace. The agent sees the task and an optional `verify` command. This is a command the agent may run to check its own work.
19
+
20
+ ## Why one run is not enough
21
+
22
+ A model gives different answers each time. One pass or one fail tells you almost nothing. So Amness repeats each task (a *trial*) and uses many tasks.
23
+
24
+ - Trials of the same task are linked, because they share the same hard parts. So Amness treats the **task** as the unit. The intervals are resampled over tasks, and comparisons are paired by task.
25
+ - With few tasks, only large differences can be seen. The report prints this limit at the bottom. With 13 tasks, only differences above about 55 points can be detected.
26
+
27
+ ## Run your first eval
28
+
29
+ 1. Check that every built-in task can be solved. This calls no model and costs nothing.
30
+
31
+ ```bash
32
+ amness eval --selftest
33
+ ```
34
+
35
+ 2. Compare the agent with no guards (`baseline`) and the full harness (`full`) on the 13 built-in tasks. This calls your model and costs tokens. The command shows a plan and asks before it starts.
36
+
37
+ ```bash
38
+ amness eval --variants ab --trials 3
39
+ ```
40
+
41
+ 3. Read the report. Amness also saves the raw results in `.amness/evals/<time>.json`.
42
+
43
+ 4. To read a saved result again without running anything:
44
+
45
+ ```bash
46
+ amness eval --report .amness/evals/<run>.json
47
+ ```
48
+
49
+ Replace `<run>` with the file name that the command printed.
50
+
51
+ Expected output of step 1 (the first lines):
52
+
53
+ ```
54
+ ok off-by-one
55
+ ok missing-feature
56
+ ok rename-across-files
57
+ ```
58
+
59
+ Every line must start with `ok`. A line that starts with `bad` shows a task with a problem, and the reason follows. A line with the reason `unverified` means the task has no reference solution.
60
+
61
+ Use `--yes` to skip the cost question, for example in a script.
62
+
63
+ ## Read the report
64
+
65
+ The report has a table with one row per variant.
66
+
67
+ | Column | What it means |
68
+ |---|---|
69
+ | `pass [95% CI]` | Share of tasks solved. The brackets show the 95% *confidence interval* (CI): the range in which the true value probably lies. It is a bootstrap over tasks. |
70
+ | `pass^k` | The chance that k attempts at a task all pass (k is 3, or the number of trials if smaller). It is low for a variant that only succeeds sometimes. |
71
+ | `tok/solved` | Tokens used per solved task, not per run. A *token* is a small piece of text that a model reads. A variant that gives up early looks cheap per run, but it is not efficient. |
72
+ | `cache` | Share of prompt tokens that the provider served from its cache. It shows `-` if the provider reports none. |
73
+ | `steps`, `secs` | Average steps and seconds per run. |
74
+ | `pareto` | A dot marks a variant that no other variant beats on both pass rate and tokens per solved task. |
75
+
76
+ Under the table, Amness compares each variant with the baseline (the first variant, or the one you name with `--baseline`).
77
+
78
+ | Column | What it means |
79
+ |---|---|
80
+ | `Δ pass [95% CI]` | Change in pass rate, in points, with its interval. |
81
+ | `W/L/T` | Tasks where the variant won, lost or tied. |
82
+ | `p (Holm)` | The p-value of an exact sign test on the tasks where the two variants differ. Amness corrects it for the number of variants (Holm correction). |
83
+ | `Δ tok/solved` | Change in tokens per solved task. |
84
+ | `verdict` | `better`, `worse` or `inconclusive`. |
85
+
86
+ After that, "guards fired per run" shows how often each guard acted (for example nudges, loop blocks, rejected finishes and trimmed output). It helps you see why a variant behaves as it does.
87
+
88
+ ### How to read "inconclusive"
89
+
90
+ The verdict is `better` only if the whole interval is above zero and the adjusted p-value is below 0.05. It is `worse` in the mirror case. In all other cases it is `inconclusive`.
91
+
92
+ `inconclusive` means the data cannot tell. It does **not** mean the variants are equal. Add more tasks or trials before you decide.
93
+
94
+ ## Choose a task suite
95
+
96
+ `--builtin` selects the suite. The suites are small and made by us, so they test the guards. They do not replace a public benchmark.
97
+
98
+ | Suite | Command | What it has |
99
+ |---|---|---|
100
+ | `code` (default) | `amness eval --builtin code` | 13 easy tasks, such as an off-by-one bug, a rename across files and a test-weakening trap. |
101
+ | `hard` | `amness eval --builtin hard` | 6 tasks with hidden edge cases, a misleading symptom, a question to answer from a 50-file repository, a string-dispatch rename, an async-ordering bug and a slow function. |
102
+ | `adversarial` | `amness eval --builtin adversarial` | 3 prompt-injection tasks. A run passes only if the harmless job is done and the injected command never ran. |
103
+
104
+ Use `--only a,b` to run only some tasks by name.
105
+
106
+ ## Compare variants
107
+
108
+ Variants are chosen with `--variants`. You can give a preset or a comma list.
109
+
110
+ | Preset | Variants |
111
+ |---|---|
112
+ | `ab` (default) | `baseline`, `full` |
113
+ | `ablate` | `full`, then `full` with each guard or feature removed in turn |
114
+ | `all` | `baseline`, `no-gate`, `full`, `full+check`, `full+review`, and every `full-<guard>` |
115
+
116
+ Single variants:
117
+
118
+ - `baseline`: no guards and no verify gate.
119
+ - `full`: all guards and the verify gate.
120
+ - `full+check`: adds a post-edit check.
121
+ - `full+review`: adds the independent reviewer (extra model calls).
122
+ - `full+route`: exploration on a cheaper model. It needs `--cheap-model <id>`.
123
+ - `full+plugins`: every plugin from `--plugin` is active. See [Plugins](plugins.md).
124
+ - `no-gate`: guards, but no verify gate.
125
+ - `full-<guard>`: `full` with one guard or feature off. The names are `nudge`, `loop`, `compact`, `stuck`, `wrapup`, `condense`, `schedule`, `ledger`, `stagnation`, `index` and `taint`.
126
+
127
+ ### Ablations
128
+
129
+ An *ablation* switches one part off and measures what changes. Run this to remove each guard in turn:
130
+
131
+ ```bash
132
+ amness eval --variants ablate --trials 5
133
+ ```
134
+
135
+ This is a large run. `ablate` has 12 variants, so 13 tasks × 12 variants × 5 trials is 780 sessions. Check the plan line before you accept.
136
+
137
+ Measure the prompt-injection check:
138
+
139
+ ```bash
140
+ amness eval --builtin adversarial --variants full,full-taint
141
+ ```
142
+
143
+ ### Save a profile after an ablation
144
+
145
+ Add `--profile-out` to write the guards that the data says to switch off:
146
+
147
+ ```bash
148
+ amness eval --variants ablate --trials 5 --profile-out profile.json --profile-model "gpt-*"
149
+ ```
150
+
151
+ Amness prints a verdict for each guard (`remove`, `KEEP` or `keep?`) and writes `profile.json`. The command tells you to copy the file to `.amness/profile.json`. `--profile-model` is the model name or pattern that the profile applies to. The default is the configured model.
152
+
153
+ A profile based on a small suite is weak evidence. Amness prints a note about the strength of the data below the verdicts. Read it.
154
+
155
+ ## Run your own tasks
156
+
157
+ Your own tasks are the best test, because they match your code.
158
+
159
+ ### As JSON files
160
+
161
+ 1. Make a folder, for example `my-tasks`.
162
+ 2. Put one `.json` file in it for each task:
163
+
164
+ ```json
165
+ {
166
+ "name": "fix-add",
167
+ "files": {
168
+ "add.js": "exports.add = (a, b) => a - b;\n",
169
+ "test.js": "const { add } = require('./add');\nif (add(2, 3) !== 5) { console.error('wrong'); process.exit(1); }\n"
170
+ },
171
+ "task": "The add function is wrong. Fix it.",
172
+ "verify": "node test.js",
173
+ "check": "node test.js",
174
+ "solution": { "add.js": "exports.add = (a, b) => a + b;\n" }
175
+ }
176
+ ```
177
+
178
+ - `files` maps a path to its text. Amness writes these files into a fresh folder.
179
+ - `task` is what the agent reads.
180
+ - `verify` is optional. The agent may run it.
181
+ - `check` is the held-out command. Exit code 0 means pass.
182
+ - `solution` is optional. Without it, `--selftest` can only check that the check fails at the start.
183
+ - `name` is optional. The file name is the default.
184
+
185
+ 3. Check the tasks, then run them:
186
+
187
+ ```bash
188
+ amness eval --cases ./my-tasks --selftest
189
+ amness eval --cases ./my-tasks --variants ab --trials 3 --jobs 3
190
+ ```
191
+
192
+ `--jobs 3` runs three sessions at once.
193
+
194
+ In the example above, `verify` and `check` are the same command. A good held-out check tests more than `verify` does. Otherwise the agent can pass by tuning only for the command it can see.
195
+
196
+ ### As a `.ts` module
197
+
198
+ A module can use a function as the check. Export a list of cases:
199
+
200
+ ```ts
201
+ // my-tasks.ts
202
+ export default [
203
+ {
204
+ name: "write-file",
205
+ files: {},
206
+ task: "Create out.txt containing hi.",
207
+ check: async (dir: string) =>
208
+ (await import("node:fs")).readFileSync(dir + "/out.txt", "utf8") === "hi" || "wrong content",
209
+ },
210
+ ];
211
+ ```
212
+
213
+ ```bash
214
+ amness eval --cases my-tasks.ts
215
+ ```
216
+
217
+ The function gets the workspace folder. It returns `true` for a pass, or a string that explains the failure. Each case needs `name`, `files`, `task` and `check`. See [Plugins](plugins.md) for more on function checks.
218
+
219
+ ### Turn a real failure into a task
220
+
221
+ If the agent failed in your project, you can keep that failure as a test.
222
+
223
+ ```bash
224
+ amness traces --case my-bug --task "Fix the date parsing bug" --check "npm test"
225
+ ```
226
+
227
+ This copies the tracked files at git `HEAD` into `.amness/evals/cases/my-bug.json`. The `--check` command must exit 0 only when the task is really done. In the chat, `/report case my-bug` does the same for your last request. Run the result with:
228
+
229
+ ```bash
230
+ amness eval --cases .amness/evals/cases --variants ab --trials 3
231
+ ```
232
+
233
+ Files over 150 KB, binary files and lock files are left out, and the total is limited to about 1 MB. Add a `"solution"` to the JSON if you want `--selftest` to cover it.
234
+
235
+ ## Use a public benchmark (SWE-bench format)
236
+
237
+ You can load a file in the format of SWE-bench. Each line of the `.jsonl` file is one instance. Amness reads the fields `instance_id`, `repo`, `base_commit`, `problem_statement`, `test_patch`, `FAIL_TO_PASS` and `PASS_TO_PASS`.
238
+
239
+ ```bash
240
+ amness eval --suite instances.jsonl --test-cmd "python -m pytest -x -q {tests}" --install "pip install -e ." --limit 20
241
+ ```
242
+
243
+ For each instance, Amness clones the repository at the base commit and runs `--install` once. The agent works. Then Amness applies the hidden tests and runs your `--test-cmd`. The text `{tests}` is replaced by the `FAIL_TO_PASS` test ids.
244
+
245
+ - An instance that cannot be prepared is **excluded**. The report lists it in an exclusion ledger. It is never counted as a failure.
246
+ - `--limit <n>` uses only the first n instances.
247
+ - `--seed <n>` makes the bootstrap intervals the same on every run.
248
+ - `--trials <n>` runs independent attempts.
249
+
250
+ ### Check a suite for contamination
251
+
252
+ ```bash
253
+ amness eval --suite instances.jsonl --audit
254
+ ```
255
+
256
+ `--audit` calls no model. It reports instances where the fix lines appear in the problem statement, where the fix is already in the base checkout, or where the base commit is missing. It prints `leak <id>: <problem>` for each problem. The exit code is 1 if it finds any.
257
+
258
+ ### Limits for benchmarks
259
+
260
+ Most public benchmarks need a separate environment for each instance, often a Docker image. You must provide it through `--install` or a prepared image. Amness gives you the harness and the statistics. It has **not been run against a full public benchmark yet**.
261
+
262
+ ## Limits and common problems
263
+
264
+ - A real run costs real tokens. The command prints the worst case and asks first. Use `--max-tokens` and `--max-steps` (default 30) to limit each session.
265
+ - The built-in suites are small and made by us. They are a regression test for the guards, not proof of quality.
266
+ - `full+route` needs `--cheap-model`. A variant name that Amness does not know stops with an error that lists the known names.
267
+ - `--variants` and `--baseline`: if the baseline name is not among the variants, Amness uses the first variant.
268
+ - The method follows recent practice: harness choice can change cost per solved task by large factors while pass-rate differences stay small ([The Scaffold Effect in Coding Agents](https://arxiv.org/abs/2607.22585)), and task-level paired bootstrap intervals are the right uncertainty statement ([Harness or Model?](https://arxiv.org/html/2609.11987v1)).
269
+
270
+ ## More variant kinds
271
+
272
+ Besides `baseline`, `full` and the `full-<guard>` names, `--variants` accepts these kinds. All of them run the full harness with one change. They are **tested** with scripted models (`test/trackc.test.ts`). Only `strategy:` was run on a real model (see below).
273
+
274
+ | Variant | What it does |
275
+ |---|---|
276
+ | `prompt:<id>` | Replaces the system prompt with the text of `.amness/prompts/<id>.md`, or `~/.amness/prompts/<id>.md`. The id `base` keeps the built-in prompt. A block of front matter between `---` lines at the top of the file is removed. |
277
+ | `model:<id>` | Runs the full harness on another model. It needs a model by id, which `amness eval` provides. |
278
+ | `chaos:tools` | About 1 in 4 tool calls fails with `ERROR: simulated failure`. The `finish` tool is never changed. |
279
+ | `chaos:429` | About 3 in 10 model calls fail with a rate-limit error (HTTP 429). Amness retries them. |
280
+ | `chaos:args` | About 3 in 10 tool calls from the model arrive with broken JSON arguments. |
281
+ | `chaos:slow-tools` | Every tool call waits 400 ms first. |
282
+ | `strategy:<name>` | The full harness with a loop strategy: `plan-first` or `explore-then-act`. See [Plugins](plugins.md#change-the-loop-with-a-strategy). |
283
+ | `full+plugins` | The full harness with every plugin from `--plugin` active. |
284
+
285
+ Prompt ids may use letters, numbers, `.`, `_` and `-`, up to 40 characters. A project prompt wins over a user prompt with the same id. An unknown id stops the run and lists the ids found.
286
+
287
+ Example. Compare a short prompt with the built-in one:
288
+
289
+ ```bash
290
+ mkdir -p .amness/prompts
291
+ echo "You are a careful coding agent. Make the smallest change that works." > .amness/prompts/terse.md
292
+ amness eval --variants full,prompt:terse --trials 3
293
+ ```
294
+
295
+ Limits: chaos failures are random but use a fixed seed, so a run is repeatable only in its pattern, not in what the model does. A chaos variant tells you whether the harness recovers. It does not tell you how often real tools fail.
296
+
297
+ ## Custom metrics and the regression gate
298
+
299
+ **What it is.** A *metric* is a number that Amness records for every run, next to pass or fail. The report shows its mean for each variant and the paired difference to the baseline. A *regression gate* compares a new run with a saved one and exits with code 1 when things got clearly worse.
300
+
301
+ **Why.** Pass rate alone hides a lot. Two variants can pass the same tasks while one changes twice as many lines. The gate lets CI catch a drop in quality or a rise in cost.
302
+
303
+ **How to use it.**
304
+
305
+ 1. Choose metrics with `--metrics`:
306
+
307
+ ```bash
308
+ amness eval --variants full,strategy:plan-first --builtin hard --trials 3 --metrics diff-lines,tool-calls
309
+ ```
310
+
311
+ Built-in metrics:
312
+
313
+ | Metric | What it counts |
314
+ |---|---|
315
+ | `diff-lines` | Lines added or removed, compared with the task's starting files. A smaller change that still passes is usually better. |
316
+ | `tool-calls` | Tool calls the agent made. |
317
+ | `tokens-per-step` | Tokens spent per step. |
318
+ | `overclaim` | 1 when the agent's text says tests or the build passed but the task check failed. This is a text match, so it is a rough signal. |
319
+
320
+ A plugin can add more in its `metrics` field. Metrics from a loaded plugin are always recorded. An unknown name stops the run and lists the known names.
321
+
322
+ 2. Read the extra table in the report. It looks like this (the numbers are made up for the layout):
323
+
324
+ ```text
325
+ custom metrics (mean per run; Δ against full with 95% interval over tasks)
326
+ variant diff-lines tool-calls
327
+ full 22.00 11.50
328
+ strategy:plan-first 15.30 Δ -6.70 [-14.20, -0.80] 8.60 Δ -2.90 [-6.60, 0.40]
329
+ ```
330
+
331
+ The mean is taken per task first, then over tasks. The difference is paired by task. The interval is a 95% bootstrap interval over tasks. If the interval includes zero, the data cannot tell.
332
+
333
+ 3. Save a good run as your baseline. Every run saves its rows to a file:
334
+
335
+ ```bash
336
+ amness eval --variants full --builtin hard --trials 3 --out evals/baseline.json
337
+ ```
338
+
339
+ 4. In CI, run again and compare:
340
+
341
+ ```bash
342
+ amness eval --variants full --builtin hard --trials 3 --yes --gate evals/baseline.json
343
+ ```
344
+
345
+ The command prints a block called `regression gate`. It exits with 0 when every variant is `ok`, and with 1 when one `FAIL`s.
346
+
347
+ **The rules** (from `gateCompare` in `src/evals.ts`). The gate compares each variant with the same variant in the saved file. It uses only tasks that are in both files.
348
+
349
+ - **Pass rate.** It fails only when the drop is bigger than `--gate-tol` points (default 5) and the drop is clear. Clear means that the whole 95% interval over tasks is below zero. A drop above the tolerance that noise could explain gives only a `warning`.
350
+ - **Cost.** It fails when tokens per solved task grew by more than `--gate-cost` percent (default 25).
351
+ - A variant that is not in the saved file passes with the note `not in the baseline file: nothing to compare`.
352
+
353
+ Example with looser limits:
354
+
355
+ ```bash
356
+ amness eval --variants full --yes --gate evals/baseline.json --gate-tol 10 --gate-cost 40
357
+ ```
358
+
359
+ **Limits.**
360
+
361
+ - With few tasks, a real drop is often not "clear", so the gate only warns. The built-in hard suite has 6 tasks. Use more tasks, or more trials, for a gate you trust.
362
+ - Model sampling noise can move the cost figure. Use `--trials 3` or more.
363
+ - The gate and the metrics are **tested** with scripted data. They have not been run in a real CI pipeline.
364
+
365
+ ## Grade real sessions
366
+
367
+ **What it is.** An eval runs tasks that you wrote. `amness plugin grade` scores sessions that really happened, from the traces in `.amness/traces`. It makes no model call.
368
+
369
+ **Why.** It shows how the harness does on the work you actually give it.
370
+
371
+ **How to use it.**
372
+
373
+ ```bash
374
+ amness plugin grade .amness/traces
375
+ ```
376
+
377
+ Without a path, Amness reads `.amness/traces`. You can give trace files or folders. Choose graders with `--grader a,b`. Add graders from a plugin with `--plugin <file>`.
378
+
379
+ Built-in graders (in `src/grade.ts`):
380
+
381
+ | Grader | Score 1 means |
382
+ |---|---|
383
+ | `finished` | The agent called the `finish` tool. |
384
+ | `no-rejections` | No finish attempt was rejected. |
385
+ | `tool-errors` | The share of tool calls that did not fail. |
386
+ | `no-loops` | The loop detector never fired. |
387
+ | `verified-edits` | Either no file changed, or a test, build or lint command ran and did not fail. |
388
+
389
+ You will see one line per grader, such as `finished mean 62% over 8 session(s)`, and up to five of the lowest sessions with the task text.
390
+
391
+ **Limits.**
392
+
393
+ - `finished` means the `finish` tool was called. A plain chat answer does not call it, so it scores 0 there. Do not use `finished` to judge chat sessions.
394
+ - `verified-edits` looks for words such as `test`, `build` and `lint` in a shell command. It does not check that the command was the right one.
395
+ - A grader that throws is skipped for that session. Sessions with no tool calls and no steps are left out.
396
+ - **Tested** with scripted traces. Not measured on a large set of real sessions.
397
+
398
+ ## Measured results so far
399
+
400
+ Real runs, one model (`gpt-6-luna` through the OpenAI API), 2026-10-29. These are small and say little about harder tasks or other models.
401
+
402
+ | Run | Result |
403
+ |---|---|
404
+ | 13 built-in tasks × 2 trials: `baseline`, `full`, `full+review` | Pass rates 96%, 100%, 100%. Tokens per solved task: 9.2k, 8.3k, 14.7k. No pairwise difference is statistically detectable (13 tasks can only detect differences above ~55 points). `full` was cheaper than `baseline` (-971 tokens per solved task) with the same pass rate; `full+review` cost about 77% more tokens per solved task than `full` and about 2.4× the time, with no gain on these tasks. |
405
+ | Adversarial suite (3 prompt-injection tasks × 3 trials): `full`, `full-taint`, `baseline` | 100% for all three: this model did not follow the injected commands even without the taint check, so the check had nothing to catch. It remains untested whether it helps with models that are more easily led. |
406
+
407
+ What this means: the built-in tasks are too easy for this model to separate the variants, and the reviewer is not worth its cost on them. The `full+route`, ablation, `tune` and best-of-n features are not measured. Harder tasks (for example a SWE-bench-format suite with `--suite`) are needed before any guard can be shown to help or hurt. Raw results were saved under `.amness/evals/` (not committed).
408
+
409
+ ### Second round (2026-10-30): a harder suite and weaker models
410
+
411
+ `amness eval --builtin hard` has 6 tasks with hidden edge cases, a misleading symptom, a question to answer from a 50-file repository, a string-dispatch rename, an async-ordering bug and a slow function. All six have a reference solution checked by `--selftest`.
412
+
413
+ | Run | Result |
414
+ |---|---|
415
+ | `gpt-6-luna`, hard suite × 3 trials: `baseline`, `full`, `full+review` | 100% for all three. Tokens per solved task 9.7k / 11.7k / 20.5k: on a model this strong the guards cost 20% more tokens and the reviewer more than double, for no gain. |
416
+ | `gpt-4.1-mini`, hard suite × 3 trials, same three variants | 89% / 83% / 89%; the one task all variants miss (`spec-in-docs`: hidden edge cases listed only in a spec file) is missed by every variant, including the reviewer. Tokens per solved task 15.2k / 14.7k / 26.3k. No difference is detectable (6 tasks). |
417
+ | `gpt-4.1-mini`, hard suite × 2 trials, `full` against each `full-<guard>` (144 sessions) | Every comparison is inconclusive (pass-rate changes between -17 and +8 points, intervals include zero); removing `taint`, `condense`, `ledger` or `stagnation` was not worse and used fewer tokens, but 6 tasks × 2 trials cannot support removing anything. |
418
+ | Injection suite, `gpt-4o-mini`, 6 trials: `full`, `full-taint`, `baseline` | 100% for all: the model did not follow the injected commands even without the taint check. |
419
+ | Budget fix, `gpt-4.1-mini`, exploration question, cap 2,500 tokens, 8 runs | Without the final report 7 of 8 runs ended with a bare "token budget exhausted" and nothing else; with it all 8 ended with a short report of what was found and what was left (it named the right file in most), but none completed the answer (the cap was smaller than one full exploration). At caps where the task fits (6,000) both behave the same (8 of 8 answered). At 4,000, 7 of 8 answered without the report and 6 of 8 with it: wrapping up early costs a little completion when the cap is very tight (small sample). |
420
+
421
+ What this says: the guards neither help nor hurt measurably on these tasks and models; the cost overhead is real and shows even on strong models; the injection suite is too easy; and `spec-in-docs` shows a gap worth fixing (neither the reviewer nor any guard makes the model re-read the spec). `gpt-4.1-nano` and `gpt-3.5-turbo` returned HTTP 404 on this account, so they were not tested.
422
+
423
+ ### Loop strategies (2026-10-30)
424
+
425
+ Model `gpt-4.1-mini`, `--builtin hard` (6 tasks), 2 trials per task, so 12 sessions per variant. Strategies are described in [Plugins](plugins.md#change-the-loop-with-a-strategy).
426
+
427
+ | Run | Result |
428
+ |---|---|
429
+ | `full` against `strategy:explore-then-act` | `full` 92% pass, 14.4k tokens per solved task. `explore-then-act` 83% pass, 24.2k. No detectable difference. |
430
+ | `strategy:plan-first`, first version | 17% pass. A bug: a reply with only a plan text ended the run, because the loop treated it as the final answer. It is fixed with the `then` field. This result does not describe the strategy. |
431
+ | `full` against `strategy:plan-first`, after the fix, with `--metrics diff-lines,tool-calls` | `full` 83% pass, 35.8k tokens per solved task, 11.9 steps. `plan-first` 83% pass, 20.4k tokens per solved task, 9.0 steps. Pass rate: inconclusive (+0 points, interval -33 to +42). `diff-lines`: 22.0 for `full`, 15.3 for `plan-first` (difference -6.7, interval -14.2 to -0.8). `tool-calls`: 11.5 against 8.6 (difference -2.9, interval -6.6 to +0.4). |
432
+
433
+ What this says. This is one run with 12 sessions per variant. The token figure for `full` is high because of a few long runs, so the cost difference is not reliable. The smaller diff for `plan-first` is the only interval that excludes zero. This does not show that `plan-first` is better. The pass rate of `full` also changed between the two runs (92% and 83%), which shows how much the numbers move from run to run.
434
+
435
+ ## Related pages
436
+
437
+ - [Plugins](plugins.md): write eval tasks, variants, metrics, graders and strategies as code.
438
+ - [Cookbook](cookbook.md): short recipes, including comparing two variants.
439
+ - [Budgets and subagents](budgets.md): why the final report exists.
440
+ - [Features in depth](features.md): guards, replay and failure mining.
441
+
442
+ ## Next steps
443
+
444
+ - Run `amness eval --selftest`, then a small `--variants ab` run on your own tasks.
445
+ - Read [Plugins](plugins.md) to compare your own harness against `full`.
446
+ - Try the recipes in the [Cookbook](cookbook.md).
447
+
448
+ ### The `spec-in-docs` task and `strategy:spec-check` (2026-10-31)
449
+
450
+ Every variant had missed the `spec-in-docs` task (a function whose edge cases are listed only in `docs/SPEC.md`). `strategy:spec-check` makes the model, once before it finishes, open the document again, list each requirement and say how it checked it. On `gpt-4.1-mini`, 8 trials of that one task: `full` passed 0 of 8; `strategy:spec-check` passed 1 of 8, using about twice the steps (15.0 against 8.1 on average). One task and 8 trials cannot show a difference, and 1 of 8 is within noise. So this check is available (`/strategy spec-check`) but is **not** shown to help, and it is off by default. The model still misses edge cases such as unit order (`30m1h`) even after re-reading the spec; a stronger check would run the spec's examples as tests, which is a task for the model or for a plugin gate you write for your project.