simt-dev 0.7.1 → 0.8.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 (186) hide show
  1. package/CHANGELOG.md +36 -1
  2. package/README.md +169 -80
  3. package/docs/decisions/ADR-014-workspace-is-configuration.md +1 -1
  4. package/docs/decisions/ADR-025-a-baseline-is-a-region-in-a-file-the-repo-owns.md +1 -1
  5. package/docs/decisions/ADR-026-a-config-without-a-region-is-a-file-the-repo-owns.md +1 -1
  6. package/docs/decisions/ADR-027-the-one-gitattributes-line-that-is-neither-dangerous-nor-empty.md +1 -1
  7. package/docs/decisions/ADR-028-a-base-file-is-a-floor-so-the-disagreement-it-cannot-repair-becomes-a-check.md +1 -1
  8. package/docs/decisions/ADR-029-the-pins-a-repository-declares-are-its-own.md +1 -1
  9. package/docs/decisions/ADR-030-what-a-plan-does-not-ship-is-a-decision-with-a-record.md +1 -1
  10. package/docs/decisions/ADR-048-a-baseline-carries-only-keys-a-reader-honours.md +1 -1
  11. package/docs/decisions/ADR-082-the-tracker-override-is-a-manifest-key.md +1 -1
  12. package/docs/decisions/ADR-126-the-mcp-surface-stays-a-reader-so-there-is-no-write-path-to-build.md +68 -0
  13. package/docs/decisions/ADR-127-the-mcp-tool-list-is-written-by-hand-and-roots-is-not-asked-for.md +65 -0
  14. package/docs/decisions/ADR-128-a-research-plan-is-a-plan-and-the-tracker-reads-it.md +42 -0
  15. package/ecosystems/bun.json +6 -0
  16. package/ecosystems/cargo.json +25 -0
  17. package/ecosystems/composer.json +6 -0
  18. package/ecosystems/dart.json +24 -0
  19. package/ecosystems/deno.json +21 -0
  20. package/ecosystems/devcontainers.json +6 -0
  21. package/ecosystems/docker-compose.json +6 -0
  22. package/ecosystems/docker.json +6 -0
  23. package/ecosystems/dotnet.json +25 -0
  24. package/ecosystems/elixir.json +23 -0
  25. package/ecosystems/gitsubmodule.json +6 -0
  26. package/ecosystems/go.json +25 -0
  27. package/ecosystems/gradle.json +13 -0
  28. package/ecosystems/maven.json +23 -0
  29. package/ecosystems/node.json +25 -0
  30. package/ecosystems/python.json +20 -0
  31. package/ecosystems/ruby.json +23 -0
  32. package/ecosystems/swift.json +25 -0
  33. package/ecosystems/terraform.json +6 -0
  34. package/ecosystems/uv.json +6 -0
  35. package/harnesses/antigravity.json +162 -0
  36. package/harnesses/claude.json +206 -0
  37. package/harnesses/codex.json +136 -0
  38. package/harnesses/copilot.json +88 -0
  39. package/harnesses/cursor.json +140 -0
  40. package/harnesses/deepseek.json +99 -0
  41. package/harnesses/gemini.json +122 -0
  42. package/harnesses/opencode.json +173 -0
  43. package/package.json +3 -1
  44. package/rules/mdc/intake-questions.mdc +8 -0
  45. package/src/advice/advice.mjs +3 -2
  46. package/src/agenthooks/render.mjs +86 -180
  47. package/src/agents/render.mjs +15 -18
  48. package/src/api.mjs +7 -5
  49. package/src/argv.mjs +19 -0
  50. package/src/bench/ablate.mjs +3 -4
  51. package/src/bench/adapters.json +155 -113
  52. package/src/bench/adapters.mjs +466 -0
  53. package/src/bench/arms.mjs +333 -0
  54. package/src/bench/grade.mjs +12 -26
  55. package/src/bench/graders.mjs +42 -0
  56. package/src/bench/mine.mjs +17 -535
  57. package/src/bench/probe-ledger.mjs +149 -0
  58. package/src/bench/probes.catalog.mjs +918 -0
  59. package/src/bench/probes.mjs +15 -1037
  60. package/src/bench/render.mjs +111 -0
  61. package/src/bench/report.mjs +116 -971
  62. package/src/bench/run.mjs +164 -881
  63. package/src/bench/variants.mjs +4 -5
  64. package/src/bench/workspace.mjs +160 -0
  65. package/src/brief/assemble.mjs +11 -13
  66. package/src/ci/dependabot.mjs +25 -55
  67. package/src/commands/agent.mjs +1 -9
  68. package/src/commands/agenthook.mjs +66 -35
  69. package/src/commands/bench.mjs +2 -2
  70. package/src/commands/ci.mjs +11 -13
  71. package/src/commands/docs.mjs +88 -0
  72. package/src/commands/gate.mjs +10 -13
  73. package/src/commands/harness.mjs +3 -3
  74. package/src/commands/help.mjs +44 -3
  75. package/src/commands/hooks.mjs +20 -20
  76. package/src/commands/ignore.mjs +11 -7
  77. package/src/commands/impact.mjs +4 -8
  78. package/src/commands/index.mjs +49 -9
  79. package/src/commands/init-scan.mjs +90 -0
  80. package/src/commands/init.mjs +122 -104
  81. package/src/commands/lease.mjs +67 -18
  82. package/src/commands/map.mjs +10 -5
  83. package/src/commands/mcp.mjs +2 -17
  84. package/src/commands/repoindex.mjs +8 -8
  85. package/src/commands/rules.mjs +8 -4
  86. package/src/commands/shared.mjs +12 -16
  87. package/src/commands/skills.mjs +5 -6
  88. package/src/commands/skillscompile.mjs +3 -3
  89. package/src/commands/skillsinstall.mjs +5 -4
  90. package/src/commands/slice.mjs +199 -64
  91. package/src/commands/spec.mjs +78 -62
  92. package/src/commands/status.mjs +24 -12
  93. package/src/commands/sync.mjs +14 -14
  94. package/src/commands/tests.mjs +12 -12
  95. package/src/commands/tokens.mjs +19 -24
  96. package/src/commands/upgrade.mjs +8 -4
  97. package/src/commands/why.mjs +6 -13
  98. package/src/compare/hooksstate.mjs +2 -6
  99. package/src/compare/learn.mjs +3 -1
  100. package/src/decisions/index.mjs +3 -2
  101. package/src/docs/commands.mjs +65 -0
  102. package/src/ecosystem/records.mjs +219 -0
  103. package/src/explain.mjs +31 -0
  104. package/src/gates/index.mjs +385 -0
  105. package/src/graph/compile.mjs +8 -4
  106. package/src/graph/load.mjs +2 -1
  107. package/src/graph/spec.mjs +10 -8
  108. package/src/harness/records.mjs +143 -0
  109. package/src/hooks/capability.mjs +5 -3
  110. package/src/hooks/dispatcher.mjs +26 -32
  111. package/src/hooks/gates.mjs +12 -2
  112. package/src/hooks/resolve.mjs +2 -7
  113. package/src/hooks/where.mjs +2 -7
  114. package/src/identity.mjs +2 -11
  115. package/src/index/coverage.mjs +58 -0
  116. package/src/index/extract.mjs +6 -16
  117. package/src/index/gate.mjs +1 -1
  118. package/src/index/govern.mjs +26 -9
  119. package/src/index/impact.mjs +4 -8
  120. package/src/index/map.mjs +14 -15
  121. package/src/index/open.mjs +173 -0
  122. package/src/index/persist.mjs +224 -57
  123. package/src/index/store.mjs +82 -39
  124. package/src/index/tests.mjs +2 -6
  125. package/src/journal.mjs +16 -11
  126. package/src/kernel/card.mjs +37 -63
  127. package/src/kernel/checks.mjs +4 -10
  128. package/src/lease.mjs +102 -7
  129. package/src/ledger/index.mjs +124 -17
  130. package/src/mcp/paginate.mjs +33 -0
  131. package/src/mcp/schemas.mjs +512 -0
  132. package/src/mcp/server.mjs +49 -9
  133. package/src/mcp/tools-facts.mjs +326 -0
  134. package/src/mcp/tools-read.mjs +221 -0
  135. package/src/mcp/tools.mjs +4 -1005
  136. package/src/{bench → measure}/corpus.mjs +1 -1
  137. package/src/measure/metrics.mjs +236 -0
  138. package/src/measure/records.mjs +211 -0
  139. package/src/measure/stats.mjs +538 -0
  140. package/src/measure/task-schema.mjs +125 -0
  141. package/src/measure/tasks.mjs +69 -0
  142. package/src/memory/decide.mjs +6 -15
  143. package/src/memory/lesson-text.mjs +61 -0
  144. package/src/memory/lessons.mjs +29 -82
  145. package/src/name.mjs +7 -0
  146. package/src/output/index.mjs +122 -31
  147. package/src/packs/manage.mjs +15 -9
  148. package/src/plan/index.mjs +1 -1
  149. package/src/plugins.mjs +22 -16
  150. package/src/prbody.mjs +7 -11
  151. package/src/projection/loaders.mjs +7 -692
  152. package/src/projection/manifest.mjs +10 -435
  153. package/src/projection/mdc.mjs +7 -8
  154. package/src/projection/project.mjs +126 -221
  155. package/src/projection/region.mjs +561 -0
  156. package/src/projection/rules.mjs +16 -547
  157. package/src/projection/surfaces.mjs +43 -210
  158. package/src/projection/targets.mjs +5 -5
  159. package/src/repo-root.mjs +13 -1
  160. package/src/resolve/eval.mjs +2 -1
  161. package/src/resolve/fingerprint.mjs +0 -7
  162. package/src/resolve/resolve.mjs +1 -41
  163. package/src/review/critic.mjs +8 -12
  164. package/src/run.mjs +98 -0
  165. package/src/secrets.mjs +14 -22
  166. package/src/state/events.mjs +129 -0
  167. package/src/status-snapshot.mjs +233 -0
  168. package/src/status.mjs +2 -6
  169. package/src/sys/git.mjs +82 -0
  170. package/src/{bench/process.mjs → sys/proc.mjs} +28 -5
  171. package/src/testing/parsers.mjs +265 -0
  172. package/src/testing/patches.mjs +23 -0
  173. package/src/testing/paths.mjs +49 -0
  174. package/src/testing/runners.mjs +186 -0
  175. package/src/testing/vault.mjs +68 -0
  176. package/src/text/frontmatter.mjs +49 -0
  177. package/src/text/tokens.mjs +52 -0
  178. package/src/toolwords.mjs +1 -1
  179. package/src/util/fs.mjs +20 -0
  180. package/src/util/sort.mjs +12 -0
  181. package/src/workspace.mjs +3 -1
  182. package/src/write/plan.mjs +82 -0
  183. package/templates/plan/tracker.json +1 -0
  184. package/docs/decisions/ADR-033-three-plan-rows-closed-by-decision-not-by-authoring.md +0 -82
  185. package/docs/decisions/ADR-102-the-two-queued-review-rows-are-closed-by-ruling.md +0 -49
  186. package/src/bench/tasks.mjs +0 -36
@@ -25,9 +25,12 @@ import { mkdir, readFile } from 'node:fs/promises';
25
25
  import { dirname, join } from 'node:path';
26
26
 
27
27
  import { PACKAGE_ROOT } from '../workspace.mjs';
28
- import { splitFrontmatter } from '../memory/decide.mjs';
28
+ import { parseFrontmatter } from '../text/frontmatter.mjs';
29
29
  import { LOADERS } from '../projection/loaders.mjs';
30
30
  import { journaledWriteFile } from '../journal.mjs';
31
+ import { applyPlan, change } from '../write/plan.mjs';
32
+ import { readBefore } from '../diff.mjs';
33
+ import { readIfExists } from '../util/fs.mjs';
31
34
 
32
35
  /** The one agent this tool ships, and the filename stem every harness shares. */
33
36
  const AGENT_FILE = 'simt-agent.md';
@@ -149,7 +152,7 @@ function parseSimpleFront(front) {
149
152
  */
150
153
  export async function loadAgent() {
151
154
  const raw = await readFile(join(PACKAGE_ROOT, 'agents', AGENT_FILE), 'utf8');
152
- const { front, body } = splitFrontmatter(raw);
155
+ const { front, body } = parseFrontmatter(raw);
153
156
  const meta = parseSimpleFront(front ?? '');
154
157
  if (!meta.name || !meta.description) {
155
158
  throw new Error(`${AGENT_FILE} must declare a name and a description in its frontmatter`);
@@ -213,15 +216,6 @@ export function rendered(adapterRow, agent, existing) {
213
216
  return { text, action: 'updated' };
214
217
  }
215
218
 
216
- /** Read a file as UTF-8, or null when it is not there. */
217
- async function readIfExists(path) {
218
- try {
219
- return await readFile(path, 'utf8');
220
- } catch {
221
- return null;
222
- }
223
- }
224
-
225
219
  /**
226
220
  * The agent files a repository should carry, one per harness that documents an
227
221
  * agents directory, plus the companion skill file. Reads each existing file and
@@ -252,13 +246,16 @@ export async function planAgents(root, { harness } = {}) {
252
246
  * Skips files that are already unchanged. Returns the paths written.
253
247
  */
254
248
  export async function writeAgentPlan(root, journal, plan) {
255
- const written = [];
256
- for (const p of plan.filter((x) => x.action !== 'unchanged')) {
257
- await mkdir(join(root, dirname(p.path)), { recursive: true });
258
- await journaledWriteFile(root, journal, join(root, p.path), p.text);
259
- written.push(p.path);
260
- }
261
- return written;
249
+ const changes = await Promise.all(
250
+ plan
251
+ .filter((x) => x.action !== 'unchanged')
252
+ .map(async (p) => {
253
+ const path = join(root, p.path);
254
+ return change({ path, before: await readBefore(path), after: p.text, owner: 'agents', reason: p.action });
255
+ }),
256
+ );
257
+ await applyPlan(root, changes, { mode: { apply: true }, journal, commit: false });
258
+ return plan.filter((x) => x.action !== 'unchanged').map((p) => p.path);
262
259
  }
263
260
 
264
261
  /**
package/src/api.mjs CHANGED
@@ -6,16 +6,18 @@
6
6
  // same question must not get three answers, and they cannot disagree if they are
7
7
  // reading one function's return value.
8
8
  //
9
- // This is the read half only. The commands that write (`init`, `sync`, `hooks
10
- // install`, `skills install`, `upgrade`) still print their plans from the command
11
- // module, because their output is a diff a person reviews before it is applied
12
- // (ADR-001). They migrate in the next slice, when `run(ctx, input)` exists to carry
13
- // a plan back to a caller that can show it.
9
+ // The write half arrives through `run(command, input)`: a writer still renders its plan
10
+ // from the command module, because a person reviews that diff before it is applied
11
+ // (ADR-001), but a library caller now gets that plan back as text and documents instead
12
+ // of having it printed at a terminal it does not own. `run` resolves the same registry
13
+ // and calls the same handler `dispatch` does, so the two surfaces cannot answer
14
+ // differently.
14
15
  //
15
16
  // The exports map in package.json points `import 'simt-dev'` here, and keeps
16
17
  // `./src/*` because the plugin runtime and the harness shims import deep paths.
17
18
  // Removing that subpath would break them to make the surface look tidier.
18
19
 
20
+ export { run, renderText, renderJson } from './run.mjs';
19
21
  export { checkRepo, checkTargets, checkTarget, frozenFindings } from './commands/sync.mjs';
20
22
  export { diagnose, serialisedFindings } from './commands/doctor.mjs';
21
23
  export { rulesCatalogue, rulesWhyFacts } from './commands/rules.mjs';
package/src/argv.mjs CHANGED
@@ -44,6 +44,14 @@ export const BOOL_FLAGS = new Set([
44
44
  'pretty',
45
45
  'accept-conflicts',
46
46
  'backup',
47
+ // init: opt out of the agent files and the agent-hooks in one flag. The parser's
48
+ // `no-` convention spells the flag as a negation of the positive `agents`, so the
49
+ // positive name is what belongs here and `init` reads `flags.agents === false` -
50
+ // the user-facing flag stays `--no-agents`. They are the two halves of the same
51
+ // decision - which harnesses the adoption speaks to - and the standalone agents /
52
+ // agent-hooks install commands remain for a repo that wants them later. Off by
53
+ // default because the adoption writes them by default.
54
+ 'agents',
47
55
  'list',
48
56
  // tokens: measure every repository under the root, not just the one. Plan 0003 R06
49
57
  // names this flag `--workspace`, and that name has been a VALUE flag since plan
@@ -196,6 +204,10 @@ export const VALUE_FLAGS = new Set([
196
204
  // name only the author's branch knows, and the default (origin/main, then main)
197
205
  // is a guess the report states out loud rather than a question it asks.
198
206
  'base',
207
+ // slice start: the id for a prompt slice, overriding the slug derived from the
208
+ // prompt text. A value, because the derived slug is a guess a reader may want to
209
+ // pin, and a flag without a value would not say what to name the slice.
210
+ 'id',
199
211
  ]);
200
212
 
201
213
  /**
@@ -241,6 +253,11 @@ export function parse(argv) {
241
253
  const flags = {};
242
254
  const positional = [];
243
255
  let passthrough = false;
256
+ // `--` is consumed as a separator, but its presence is a fact a command may need:
257
+ // `slice start -- "<text>"` reads the prompt as everything after the marker, and a
258
+ // positional that merely happens to sit there is a different command. Carried as a
259
+ // flag so it reaches the command the way every other parsed fact does.
260
+ let dashdash = false;
244
261
 
245
262
  for (let i = 0; i < argv.length; i += 1) {
246
263
  const arg = argv[i];
@@ -251,6 +268,7 @@ export function parse(argv) {
251
268
  }
252
269
  if (arg === '--') {
253
270
  passthrough = true;
271
+ dashdash = true;
254
272
  continue;
255
273
  }
256
274
 
@@ -316,6 +334,7 @@ export function parse(argv) {
316
334
  return { ok: false, error: usage(`unknown flag --${raw}`) };
317
335
  }
318
336
 
337
+ if (dashdash) flags.dashdash = true;
319
338
  return { ok: true, value: { flags, positional } };
320
339
  }
321
340
 
@@ -19,15 +19,14 @@ import { plan } from '../projection/project.mjs';
19
19
  import { isEligible, loadRules, readDeclared, ruleValues, select } from '../projection/rules.mjs';
20
20
  import { resolveSurfaces, rulePath, SURFACES } from '../projection/surfaces.mjs';
21
21
  import { fingerprint } from '../resolve/fingerprint.mjs';
22
+ import { evaluateRunRecord, loadPrices } from '../measure/metrics.mjs';
23
+ import { loadRunRecords } from '../measure/records.mjs';
22
24
  import {
23
25
  DEFAULT_BOOTSTRAP_SAMPLES,
24
26
  DEFAULT_BOOTSTRAP_SEED,
25
27
  compareArms,
26
- evaluateRunRecord,
27
28
  holmAdjust,
28
- loadPrices,
29
- loadRunRecords,
30
- } from './report.mjs';
29
+ } from '../measure/stats.mjs';
31
30
 
32
31
  export const DEFAULT_CANARY_SIZE = 10;
33
32
  export const DEL_R_TOLERANCE = 0.01;
@@ -1,165 +1,207 @@
1
1
  {
2
- "schemaVersion": 1,
2
+ "schemaVersion": 2,
3
3
  "adapters": {
4
4
  "claude": {
5
5
  "id": "claude",
6
6
  "label": "Claude Code",
7
- "kind": "cli",
7
+ "kind": "agent",
8
8
  "bin": "claude",
9
- "template": "claude -p \"{prompt}\" --output-format json --max-turns {turns}",
10
- "args": ["-p", "{prompt}", "--output-format", "json", "--max-turns", "{turns}"],
11
- "modelArgs": ["--model", "{model}"],
12
- "format": "json",
9
+ "prompt": {
10
+ "delivery": "argv",
11
+ "args": ["-p", "{prompt}", "--output-format", "json", "--max-turns", "{turns}"],
12
+ "modelArgs": ["--model", "{model}"]
13
+ },
14
+ "env": { "allow": ["ANTHROPIC_API_KEY"] },
13
15
  "isolation": "env",
14
- "env": ["ANTHROPIC_API_KEY"],
15
- "usageSource": "usage.*, total_cost_usd, num_turns",
16
- "fields": {
17
- "input": ["usage.input_tokens", "usage.input"],
18
- "cacheWrite": ["usage.cache_creation_input_tokens", "usage.cacheWrite"],
19
- "cacheRead": ["usage.cache_read_input_tokens", "usage.cacheRead"],
20
- "output": ["usage.output_tokens", "usage.output"],
21
- "turns": ["num_turns", "usage.turns"],
22
- "toolCalls": ["num_tool_calls", "tool_calls", "usage.toolCalls"],
23
- "costUsd": ["total_cost_usd", "cost_usd", "costUsd"]
24
- }
16
+ "timeoutMs": 120000,
17
+ "usage": {
18
+ "format": "json",
19
+ "fields": {
20
+ "input": ["usage.input_tokens", "usage.input"],
21
+ "cacheWrite": ["usage.cache_creation_input_tokens", "usage.cacheWrite"],
22
+ "cacheRead": ["usage.cache_read_input_tokens", "usage.cacheRead"],
23
+ "output": ["usage.output_tokens", "usage.output"],
24
+ "turns": ["num_turns", "usage.turns"],
25
+ "toolCalls": ["num_tool_calls", "tool_calls", "usage.toolCalls"],
26
+ "costUsd": ["total_cost_usd", "cost_usd", "costUsd"]
27
+ }
28
+ },
29
+ "transcript": { "sources": ["stdout"] }
25
30
  },
26
31
  "codex": {
27
32
  "id": "codex",
28
33
  "label": "Codex",
29
- "kind": "cli",
34
+ "kind": "agent",
30
35
  "bin": "codex",
31
- "template": "codex exec --json \"{prompt}\"",
32
- "args": ["exec", "--json", "{prompt}"],
33
- "modelArgs": ["--model", "{model}"],
34
- "format": "jsonl",
36
+ "prompt": {
37
+ "delivery": "argv",
38
+ "args": ["exec", "--json", "{prompt}"],
39
+ "modelArgs": ["--model", "{model}"]
40
+ },
41
+ "env": { "allow": ["OPENAI_API_KEY"] },
35
42
  "isolation": "env",
36
- "env": ["OPENAI_API_KEY"],
37
- "usageSource": "token events in JSONL",
38
- "fields": {
39
- "input": ["usage.input_tokens", "input_tokens", "usage.input"],
40
- "cacheWrite": ["usage.cache_creation_input_tokens", "usage.cache_write_input_tokens", "cache_write_input_tokens"],
41
- "cacheRead": ["usage.cached_input_tokens", "usage.cache_read_input_tokens", "cached_input_tokens"],
42
- "output": ["usage.output_tokens", "output_tokens", "usage.output"],
43
- "turns": ["turns", "num_turns"],
44
- "toolCalls": ["tool_calls", "num_tool_calls"],
45
- "costUsd": ["total_cost_usd", "cost_usd", "cost"]
46
- }
43
+ "timeoutMs": 120000,
44
+ "usage": {
45
+ "format": "jsonl",
46
+ "fields": {
47
+ "input": ["usage.input_tokens", "input_tokens", "usage.input"],
48
+ "cacheWrite": ["usage.cache_creation_input_tokens", "usage.cache_write_input_tokens", "cache_write_input_tokens"],
49
+ "cacheRead": ["usage.cached_input_tokens", "usage.cache_read_input_tokens", "cached_input_tokens"],
50
+ "output": ["usage.output_tokens", "output_tokens", "usage.output"],
51
+ "turns": ["turns", "num_turns"],
52
+ "toolCalls": ["tool_calls", "num_tool_calls"],
53
+ "costUsd": ["total_cost_usd", "cost_usd", "cost"]
54
+ },
55
+ "events": {
56
+ "turns": [{ "type": "turn.completed" }],
57
+ "toolCalls": [
58
+ { "type": "item.completed", "item.type": ["command_execution", "tool_call", "mcp_tool_call"] }
59
+ ]
60
+ }
61
+ },
62
+ "transcript": { "sources": ["stdout"] }
47
63
  },
48
64
  "gemini": {
49
65
  "id": "gemini",
50
66
  "label": "Gemini CLI",
51
- "kind": "cli",
67
+ "kind": "agent",
52
68
  "bin": "gemini",
53
- "template": "gemini -p \"{prompt}\" --output-format json",
54
- "args": ["-p", "{prompt}", "--output-format", "json"],
55
- "modelArgs": ["--model", "{model}"],
56
- "format": "json",
69
+ "prompt": {
70
+ "delivery": "argv",
71
+ "args": ["-p", "{prompt}", "--output-format", "json"],
72
+ "modelArgs": ["--model", "{model}"]
73
+ },
74
+ "env": { "allow": ["GEMINI_API_KEY", "GOOGLE_API_KEY"] },
57
75
  "isolation": "env",
58
- "env": ["GEMINI_API_KEY", "GOOGLE_API_KEY"],
59
- "usageSource": "stats block",
60
- "fields": {
61
- "input": ["stats.inputTokens", "stats.tokens.prompt", "stats.prompt_tokens", "usage.input_tokens"],
62
- "cacheWrite": ["stats.cacheWriteTokens", "stats.tokens.cacheWrite", "usage.cache_creation_input_tokens"],
63
- "cacheRead": ["stats.cachedTokens", "stats.tokens.cached", "usage.cache_read_input_tokens"],
64
- "output": ["stats.outputTokens", "stats.tokens.candidates", "stats.completion_tokens", "usage.output_tokens"],
65
- "turns": ["stats.turns", "stats.totalTurns", "num_turns"],
66
- "toolCalls": ["stats.toolCalls", "stats.tools.totalCalls", "num_tool_calls"],
67
- "costUsd": ["stats.totalCostUsd", "stats.costUsd", "total_cost_usd"]
68
- }
76
+ "timeoutMs": 120000,
77
+ "usage": {
78
+ "format": "json",
79
+ "fields": {
80
+ "input": ["stats.inputTokens", "stats.tokens.prompt", "stats.prompt_tokens", "usage.input_tokens"],
81
+ "cacheWrite": ["stats.cacheWriteTokens", "stats.tokens.cacheWrite", "usage.cache_creation_input_tokens"],
82
+ "cacheRead": ["stats.cachedTokens", "stats.tokens.cached", "usage.cache_read_input_tokens"],
83
+ "output": ["stats.outputTokens", "stats.tokens.candidates", "stats.completion_tokens", "usage.output_tokens"],
84
+ "turns": ["stats.turns", "stats.totalTurns", "num_turns"],
85
+ "toolCalls": ["stats.toolCalls", "stats.tools.totalCalls", "num_tool_calls"],
86
+ "costUsd": ["stats.totalCostUsd", "stats.costUsd", "total_cost_usd"]
87
+ },
88
+ "totals": [
89
+ {
90
+ "root": "stats.models",
91
+ "keys": { "input": "tokens.prompt", "cacheRead": "tokens.cached", "output": "tokens.candidates" }
92
+ }
93
+ ]
94
+ },
95
+ "transcript": { "sources": ["stdout"] }
69
96
  },
70
97
  "opencode": {
71
98
  "id": "opencode",
72
99
  "label": "opencode",
73
- "kind": "cli",
100
+ "kind": "agent",
74
101
  "bin": "opencode",
75
- "template": "opencode run \"{prompt}\"",
76
- "args": ["run", "--format", "json", "{prompt}"],
77
- "modelArgs": ["--model", "{model}"],
78
- "format": "jsonl",
102
+ "prompt": {
103
+ "delivery": "argv",
104
+ "args": ["run", "--format", "json", "{prompt}"],
105
+ "modelArgs": ["--model", "{model}"]
106
+ },
107
+ "env": { "allow": ["OPENAI_API_KEY", "ANTHROPIC_API_KEY"] },
79
108
  "isolation": "env",
80
- "env": ["OPENAI_API_KEY", "ANTHROPIC_API_KEY"],
81
- "usageSource": "session export",
82
- "fields": {
83
- "input": ["tokens.input", "usage.input_tokens", "part.tokens.input"],
84
- "cacheWrite": ["tokens.cache.write", "usage.cache_creation_input_tokens", "part.tokens.cache.write"],
85
- "cacheRead": ["tokens.cache.read", "usage.cache_read_input_tokens", "part.tokens.cache.read"],
86
- "output": ["tokens.output", "usage.output_tokens", "part.tokens.output"],
87
- "turns": ["turns", "num_turns"],
88
- "toolCalls": ["toolCalls", "num_tool_calls"],
89
- "costUsd": ["cost", "part.cost", "total_cost_usd"]
90
- }
109
+ "timeoutMs": 120000,
110
+ "usage": {
111
+ "format": "jsonl",
112
+ "fields": {
113
+ "input": ["tokens.input", "usage.input_tokens", "part.tokens.input"],
114
+ "cacheWrite": ["tokens.cache.write", "usage.cache_creation_input_tokens", "part.tokens.cache.write"],
115
+ "cacheRead": ["tokens.cache.read", "usage.cache_read_input_tokens", "part.tokens.cache.read"],
116
+ "output": ["tokens.output", "usage.output_tokens", "part.tokens.output"],
117
+ "turns": ["turns", "num_turns"],
118
+ "toolCalls": ["toolCalls", "num_tool_calls"],
119
+ "costUsd": ["cost", "part.cost", "total_cost_usd"]
120
+ },
121
+ "events": {
122
+ "turns": [{ "type": "step_finish" }, { "event": "message_send" }],
123
+ "toolCalls": [{ "type": "tool_use" }]
124
+ }
125
+ },
126
+ "transcript": { "sources": ["stdout"] }
91
127
  },
92
128
  "cursor": {
93
129
  "id": "cursor",
94
130
  "label": "Cursor CLI",
95
- "kind": "cli",
131
+ "kind": "agent",
96
132
  "bin": "cursor-agent",
97
- "template": "cursor-agent -p \"{prompt}\" --output-format json",
98
- "args": ["-p", "{prompt}", "--output-format", "json"],
99
- "modelArgs": ["--model", "{model}"],
100
- "format": "json",
133
+ "prompt": {
134
+ "delivery": "argv",
135
+ "args": ["-p", "{prompt}", "--output-format", "json"],
136
+ "modelArgs": ["--model", "{model}"]
137
+ },
138
+ "env": { "allow": ["CURSOR_API_KEY"] },
101
139
  "isolation": "env",
102
- "env": ["CURSOR_API_KEY"],
103
- "usageSource": "result JSON",
104
- "fields": {
105
- "input": ["usage.input_tokens", "usage.input", "stats.inputTokens"],
106
- "cacheWrite": ["usage.cache_creation_input_tokens", "usage.cacheWrite", "stats.cacheWriteTokens"],
107
- "cacheRead": ["usage.cache_read_input_tokens", "usage.cacheRead", "stats.cachedTokens"],
108
- "output": ["usage.output_tokens", "usage.output", "stats.outputTokens"],
109
- "turns": ["num_turns", "turns", "usage.turns"],
110
- "toolCalls": ["num_tool_calls", "tool_calls", "usage.toolCalls", "toolCalls"],
111
- "costUsd": ["total_cost_usd", "costUsd", "cost_usd"]
112
- }
140
+ "timeoutMs": 120000,
141
+ "usage": {
142
+ "format": "json",
143
+ "fields": {
144
+ "input": ["usage.input_tokens", "usage.input", "stats.inputTokens"],
145
+ "cacheWrite": ["usage.cache_creation_input_tokens", "usage.cacheWrite", "stats.cacheWriteTokens"],
146
+ "cacheRead": ["usage.cache_read_input_tokens", "usage.cacheRead", "stats.cachedTokens"],
147
+ "output": ["usage.output_tokens", "usage.output", "stats.outputTokens"],
148
+ "turns": ["num_turns", "turns", "usage.turns"],
149
+ "toolCalls": ["num_tool_calls", "tool_calls", "usage.toolCalls", "toolCalls"],
150
+ "costUsd": ["total_cost_usd", "costUsd", "cost_usd"]
151
+ }
152
+ },
153
+ "transcript": { "sources": ["stdout"] }
113
154
  },
114
155
  "aider": {
115
156
  "id": "aider",
116
157
  "label": "Aider",
117
- "kind": "cli",
158
+ "kind": "agent",
118
159
  "bin": "aider",
119
- "template": "aider --message \"{prompt}\" --yes-always",
120
- "args": ["--message", "{prompt}", "--yes-always", "--analytics-log", "{analyticsLog}"],
121
- "modelArgs": ["--model", "{model}"],
122
- "format": "analytics-log",
160
+ "prompt": {
161
+ "delivery": "argv",
162
+ "args": ["--message", "{prompt}", "--yes-always", "--analytics-log", "{analyticsLog}"],
163
+ "modelArgs": ["--model", "{model}"]
164
+ },
165
+ "env": { "allow": ["OPENAI_API_KEY", "ANTHROPIC_API_KEY"] },
123
166
  "isolation": "env",
124
- "env": ["OPENAI_API_KEY", "ANTHROPIC_API_KEY"],
125
- "usageSource": "--analytics-log file",
126
- "fields": {
127
- "input": ["prompt_tokens", "properties.prompt_tokens", "usage.input_tokens"],
128
- "cacheWrite": ["cache_creation_input_tokens", "properties.cache_write_tokens"],
129
- "cacheRead": ["cache_read_input_tokens", "properties.cache_read_tokens"],
130
- "output": ["completion_tokens", "properties.completion_tokens", "usage.output_tokens"],
131
- "turns": ["turns", "properties.turns"],
132
- "toolCalls": ["tool_calls", "properties.tool_calls"],
133
- "costUsd": ["cost", "total_cost", "properties.cost", "properties.total_cost"]
134
- }
167
+ "timeoutMs": 120000,
168
+ "usage": {
169
+ "format": "analytics-log",
170
+ "fields": {
171
+ "input": ["prompt_tokens", "properties.prompt_tokens", "usage.input_tokens"],
172
+ "cacheWrite": ["cache_creation_input_tokens", "properties.cache_write_tokens"],
173
+ "cacheRead": ["cache_read_input_tokens", "properties.cache_read_tokens"],
174
+ "output": ["completion_tokens", "properties.completion_tokens", "usage.output_tokens"],
175
+ "turns": ["turns", "properties.turns"],
176
+ "toolCalls": ["tool_calls", "properties.tool_calls"],
177
+ "costUsd": ["cost", "total_cost", "properties.cost", "properties.total_cost"]
178
+ }
179
+ },
180
+ "transcript": { "sources": ["stdout", "analytics"] }
135
181
  },
136
182
  "gold": {
137
183
  "id": "gold",
138
184
  "label": "Gold Oracle",
139
- "kind": "builtin",
185
+ "kind": "oracle",
186
+ "oracle": { "from": "vault" },
140
187
  "bin": null,
141
- "template": null,
142
- "args": [],
143
- "modelArgs": [],
144
- "format": "builtin",
188
+ "prompt": { "delivery": "argv", "args": [], "modelArgs": [] },
189
+ "env": { "allow": [] },
145
190
  "isolation": "none",
146
- "env": [],
147
- "usageSource": "vault gold.patch",
148
- "fields": {}
191
+ "usage": { "format": "none", "fields": {}, "fixed": { "turns": 1, "toolCalls": 1 } },
192
+ "transcript": { "sources": [] }
149
193
  },
150
194
  "noop": {
151
195
  "id": "noop",
152
196
  "label": "No-op Baseline",
153
- "kind": "builtin",
197
+ "kind": "oracle",
198
+ "oracle": { "from": "none" },
154
199
  "bin": null,
155
- "template": null,
156
- "args": [],
157
- "modelArgs": [],
158
- "format": "builtin",
200
+ "prompt": { "delivery": "argv", "args": [], "modelArgs": [] },
201
+ "env": { "allow": [] },
159
202
  "isolation": "none",
160
- "env": [],
161
- "usageSource": "none",
162
- "fields": {}
203
+ "usage": { "format": "none", "fields": {} },
204
+ "transcript": { "sources": [] }
163
205
  }
164
206
  }
165
207
  }