@garuda-agent/garuda 0.17.0 → 0.18.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 (30) hide show
  1. package/CHANGELOG.md +137 -0
  2. package/README.md +1 -1
  3. package/SECURITY.md +1 -1
  4. package/dist/{acpCommand-7EY3NHPG.js → acpCommand-IUZPLPLI.js} +16 -16
  5. package/dist/{chunk-JRVWH27M.js → chunk-2FIV2VZP.js} +7 -3
  6. package/dist/{chunk-TJIWD7R7.js → chunk-4BVCYCQT.js} +3 -3
  7. package/dist/{chunk-U65DQZDB.js → chunk-65NUEOI7.js} +2 -2
  8. package/dist/{chunk-J4346IDH.js → chunk-7KBOIPUT.js} +2 -1
  9. package/dist/chunk-C57GHLKP.js +9 -0
  10. package/dist/chunk-DOCDCQVM.js +484 -0
  11. package/dist/chunk-FOPBOB7W.js +332 -0
  12. package/dist/{chunk-2DYMJMRQ.js → chunk-NHWHG3SW.js} +60 -20
  13. package/dist/{chunk-Z66BWTMD.js → chunk-OQ26W5L4.js} +4 -4
  14. package/dist/chunk-Q4P3W657.js +6372 -0
  15. package/dist/{chunk-ZAE25JM2.js → chunk-QANRZW7W.js} +8 -1
  16. package/dist/{chunk-735BKABA.js → chunk-UKIE4AAM.js} +2 -2
  17. package/dist/cli/index.js +67 -34
  18. package/dist/config-WV2H64TF.js +23 -0
  19. package/dist/evalCommand-SKJQ6CW2.js +686 -0
  20. package/dist/evalTune-CZRCPSZ3.js +295 -0
  21. package/dist/{inkChat-FNUBK43U.js → inkChat-WYYAFZXD.js} +13 -13
  22. package/dist/{jobCommand-FE6XN3YD.js → jobCommand-2ODQLHB3.js} +4 -4
  23. package/dist/{manager-73MPYFTP.js → manager-TCYTA5XU.js} +10 -10
  24. package/dist/{nightCommand-OODJNWDT.js → nightCommand-WJU6VZA6.js} +4 -4
  25. package/dist/{run-ML6GSPN4.js → run-PTMRQCIU.js} +5 -5
  26. package/dist/{setupCommand-GBQIVYJC.js → setupCommand-YMF6I3MD.js} +4 -4
  27. package/dist/tune-YVI2KWQF.js +31 -0
  28. package/package.json +1 -1
  29. package/dist/chunk-BSK5T2ZG.js +0 -9
  30. package/dist/evalCommand-YVQAWUZE.js +0 -2833
package/CHANGELOG.md CHANGED
@@ -1,5 +1,142 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.18.0 (2026-11-04)
4
+
5
+ - Biome 2.6.2 (with @inquirer/prompts 8.7.4, react 19.3.1 and smol-toml 1.9.1, from Dependabot's
6
+ group update). Biome 2.6 formats Markdown and YAML by default: Markdown formatting is off (the
7
+ docs keep their own layout), and pnpm's lockfiles are left out.
8
+ - Dependabot: `@types/node` stays on the oldest supported Node line (no major updates); each other
9
+ major update comes as its own pull request.
10
+ - The Homebrew formula in the repository names 0.17.0 and its tarball hash.
11
+ - Eval evidence, part 1 (T11a): the report gives the pass rate over all attempts with a 95%
12
+ interval (a cluster bootstrap over tasks, so repeats of one task count together), the tasks that
13
+ passed every run or none, the median and p95 of steps, tokens and time, the cost per accepted
14
+ change (all attempts divided by the passes), and unexpected changes (files that a run changed
15
+ but the task did not need; a new `allowChanges` field widens a task's scope). `--shuffle` and
16
+ `--seed` set the run order. `report.json` is version 2, with Garuda's version and commit, the
17
+ model, the OS, the seed, the run order and a hash of each task. A run whose every attempt failed
18
+ with an error gives no interval ("No scored run"), a task with only error runs is not counted as
19
+ "passed none", and an authentication error (401 or 403, for example a refused API key) stops the
20
+ eval at the first run instead of failing every run the same way.
21
+ - `garuda eval compare <a> <b>` (T11a part 2): two reports of the same tasks side by side, the
22
+ difference of the pass rates (B − A) with a paired 95% interval, and each arm's cost per accepted
23
+ change, unexpected changes and median time. It refuses reports whose tasks differ, and a
24
+ difference whose interval contains 0 is "no clear difference". The run report now says when its
25
+ interval is only a rough guide (fewer than 10 tasks, or every draw gave the same rate).
26
+ - The Claude Code baseline (T11b): `garuda eval --agent claude-code` runs `claude -p` on the same
27
+ tasks with the same scratch folders, time limit and grading, so `garuda eval compare` can set
28
+ Garuda against Claude Code. Claude Code runs with every tool allowed, so only in the OS sandbox,
29
+ with network only to `api.anthropic.com`, a new config folder per run, and the API key in its
30
+ environment only. Its turns, tokens and cost come from its JSON result. `eval compare` prints a
31
+ zero difference as "0 pts" and says when every draw gave the same difference. The user's first
32
+ live baseline run found that the proxy for `api.anthropic.com` started only in a Garuda turn, so
33
+ Claude Code had no network: the runner now starts it first (`Runtime.prepareCommands`). An eval
34
+ now also stops at the first run that cannot reach the API (a refused connection, an unknown
35
+ host, a certificate error), as it does for a refused key.
36
+ - `garuda eval compare` also compares the cost per accepted change: the ratio B/A with a paired
37
+ 95% interval, and a verdict ("B costs more", "B costs less" or "no clear difference"). An unknown
38
+ cost gives no ratio. The hard-coupon task allows changes in the coupon module and the API routes
39
+ (`allowChanges`): both agents made them in the first baseline runs. Its task hash changes, so
40
+ compare new hard-suite runs only with new ones.
41
+ - A held-out set (T11c): 10 new, harder tasks in TypeScript, Python and Java, apart from every
42
+ suite. `--split heldout` runs them, `--split all` runs them with the dev tasks, and a plain
43
+ `garuda eval` never does (a held-out id with `-t` is refused with the fix). They cover a defect
44
+ whose cause is in another file (3), a refactor across modules (2), tests that a mutation check
45
+ must find good enough (2), conventions from the repository's `AGENTS.md` that a hidden test
46
+ checks (2), and a vague request (1). Each task's hash is recorded in the tests: a changed task
47
+ must change its hash on purpose, and a tuning result seen before the change is invalid.
48
+ `report.json` records the split. `--list` shows the held-out set. The compare note now says
49
+ "the same pass-rate difference".
50
+ - The first held-out run (Haiku 5.5, 3 runs a task: 27/30) found a fault in one task:
51
+ the export-dates task (now `med-export-dates`) failed 0/3 only because the agent, with the right fix each time, added a CSV
52
+ test to the protected test file. Its hidden test decides, so the visible tests are no longer
53
+ protected, and a new test is in scope there and in the two conventions tasks. The hashes of these
54
+ three tasks change: compare held-out runs only with runs made after this change.
55
+ - A harder held-out set (T11c, second version). The first set was at its ceiling for Haiku 5.5,
56
+ so it is now a dev suite, `-s medium` (ids `med-…`), and 10 new tasks took its place. Each has a
57
+ trap: a quick fix that passes the visible tests fails the hidden test or the mutation check (a
58
+ cache key without the currency, a new idempotency key per retry, invoice shares and yen, a
59
+ command registry with unchanged output, settings by the README's rules, 6 subtle mutants in two
60
+ test-writing tasks, a migration and a reset endpoint by `AGENTS.md`, and a slow search that must
61
+ keep every result). Their ids start with `held-out-`. The tests prove each trap. Compare
62
+ held-out runs only with runs made after this change. The run report's id column now fits the
63
+ longest id, so the columns after it line up.
64
+ - The second held-out run (Haiku 5.5, 3 runs a task: 28/30) found two faults, both in the checks.
65
+ `held-out-conventions-migration` failed 2/3 with correct work: the agent named the field
66
+ `dueAt` (as `created_at` suggests), and the hidden test read `dueDate`, which the prompt never
67
+ named. The prompt now names it. The report gave "The check failed:" with nothing after it: a
68
+ guard stopped the check with no output. Each guard now prints what is missing, and a check with
69
+ no output reports its exit code. Four held-out hashes change.
70
+ - Tests: `test/evals.test.ts` self-tests the basic and hard suites only (the medium tasks ran twice
71
+ there), with 60 s for each task. The user's `pnpm check` timed out on `hard-rounding` at 5 s,
72
+ then on the LSP reference sample. `vitest.config.ts` now gives every test 30 s, the limit that
73
+ the release checks used, so `pnpm check` agrees with them.
74
+ - The third held-out run, with the Claude Code baseline, ran an old build: `dist/` was older than
75
+ the checkout, so the old tasks ran, and `report.json` named the checkout's commit, not the
76
+ build's. A build now records the commit it came from (tsup sets it), `report.json` gives it as
77
+ `garuda.commit` and adds `garuda.checkout` when the checkout differs, and `garuda eval` warns
78
+ at the start: "This build is from commit …, but the checkout is at …: run pnpm build first."
79
+ - Held-out prompts with visible tests now say "You may add tests in new files, but do not change
80
+ the existing test files": in the same run the agent appended a correct test to a protected test
81
+ file after "do not change the existing ones". Five held-out hashes change.
82
+ - Same run, same (old) tasks, Haiku 5.5: Garuda 26/30, Claude Code 27/30, no clear difference in
83
+ the pass rate; Claude Code cost ×1.50 per accepted change (paired interval ×1.35 to ×1.71).
84
+ - Design (T11; T11a and T11b built, T11c–d not yet): eval evidence — intervals and consistency over repeated runs, cost per
85
+ accepted change, unexpected changes, a Claude Code baseline runner, a held-out task split, and a
86
+ proposer loop that edits only a prompt addendum (`docs/lld/eval-evidence.md`).
87
+
88
+ - An eval A/B of one MCP server: `garuda eval --mcp <server>` allows that one server from your
89
+ own `~/.garuda/mcp.json` (no other server, and none from a project file), and
90
+ `--mcp-prepare <command>` runs a command in each scratch folder, in the sandbox, before the agent
91
+ starts; what it writes is not counted as the agent's change. For Graphify:
92
+ `--mcp graphify --mcp-prepare "graphify update ."`. Each run records its MCP tool calls; the
93
+ report and `eval compare` show them ("the agent never used the server" when none), compare notes
94
+ when the arms' servers differ, and `report.json` records the server and the command. A server
95
+ that does not start, or a failed prepare command, stops the eval at the first run. The Claude
96
+ Code baseline refuses both options.
97
+ - The prepare command now runs before the agent's runtime starts, so a note that it writes into
98
+ `GARUDA.md` reaches the agent (the user's first Graphify run: the agent never called the server,
99
+ and a note written later would not have been read). A `~/.garuda/mcp.json` whose `"servers"` is a
100
+ list now gets a message that shows the right form, not "expected record, received array".
101
+ - Docs: Graphify as an example MCP server in the tools guide (install, `mcp.json`, the note in
102
+ `GARUDA.md`, and what we measured: ×1.28 cost per accepted change on the hard suite, no change in
103
+ passes). Garuda does not include it. The T11d design gets the user's keep rule: an edit with the
104
+ same passes stays when its cost per accepted change is clearly lower.
105
+ - Tests: `waitUntil` waits up to 20 s by default (it was 5 s), under the 30 s test limit. The
106
+ user's `pnpm check` failed the M5 Ctrl-C test on a busy machine. Two test files had their own
107
+ copy with 4 or 5 s (a second M5 Ctrl-C test then failed the same way); they use `waitUntil`
108
+ now, and a test refuses a new copy.
109
+
110
+ - The proposer loop (T11d): `garuda eval tune --addendum <file>` improves a prompt addendum. A
111
+ proposer model (default `claude-opus-5-5`) reads the dev runs that failed, or each task's cost
112
+ when all passed, and writes a new version; it stays when no task goes from all runs to none and
113
+ it passes 2 more runs (`--margin`) or as many at a clearly lower cost per accepted change (the
114
+ user's rule). Texts that ask to skip or edit tests or checks, or to leave the sandbox, are
115
+ refused before a run; the proposer never sees the held-out tasks; `--max-cost` (default $20)
116
+ stops before a round that would pass it. At the end the held-out set compares no addendum with
117
+ the final one. Garuda never edits the file: the versions, inputs, reports and history go to
118
+ `.garuda/evals/tune-<id>/`. `garuda eval --addendum <file>` runs any suite with an addendum.
119
+ - `eval tune` after the user's first run (Haiku 5.5 agent, Opus 5.5 proposer, $0.65): the kept
120
+ version cut the held-out cost per accepted change to ×0.81 (×0.75 to ×0.88), all runs passing.
121
+ The run also found four faults, now fixed: two of three proposals were refused for phrases in
122
+ rules against cheating ("never modify tests to make them pass") or about reading ("skip tests
123
+ you won't run"), so a negation now clears a phrase and a refused text gets one more try in the
124
+ round; the held-out comparison said the reports had no task hashes; runs went one at a time
125
+ (about 16 minutes a score), so `--parallel` (default 4) runs them together; and nothing printed
126
+ during a score, so each run prints a line. Two runs of one task at the same time can no longer
127
+ take the same session file name (also for `garuda eval --parallel`).
128
+
129
+ - The system prompt tells the agent how to work in few steps: batch tool calls that do not depend
130
+ on each other, find before reading, no exploration with bash, all edits in one step, one narrow
131
+ test run, fix the code not the tests, stop when done. The rules come from the first
132
+ `garuda eval tune` run: on the held-out set, with every run passing, they cut the cost per
133
+ accepted change to ×0.81 (95% interval ×0.75 to ×0.88) with Haiku 5.5 and ×0.87 (×0.79 to
134
+ ×0.95) with Sonnet 5.5. The tuned text's rules against `remember` and for one-sentence answers
135
+ are left out: they served the evals, not users. The prompt's own wording, measured against
136
+ 0.17.0's prompt on the held-out set (3 runs a task, seed 7): with Sonnet 5.5, 30/30 both and
137
+ ×0.90 (×0.84 to ×0.96); with Haiku 5.5, 30/30 and 29/30 (one miss of the invoice refund trap)
138
+ and ×0.88 (×0.79 to ×1.02), so the Haiku saving is likely but not shown with confidence.
139
+
3
140
  ## 0.17.0 (2026-10-27)
4
141
 
5
142
  - macOS: no command process outlives the command (IPI-04). Seatbelt has no process namespace, so a
package/README.md CHANGED
@@ -7,7 +7,7 @@ Website and docs: https://madhu-sv.github.io/garuda/
7
7
  Garuda is a coding agent for the terminal, and for editors over the Agent Client Protocol. It reads
8
8
  and edits your code, runs commands in an OS sandbox, and keeps an audit log of its permission
9
9
  decisions. It works with Claude and with OpenAI-compatible models, local ones too. This is version
10
- 0.17.0. Release notes: [CHANGELOG.md](CHANGELOG.md).
10
+ 0.18.0. Release notes: [CHANGELOG.md](CHANGELOG.md).
11
11
 
12
12
  ## What Garuda does on your machine
13
13
 
package/SECURITY.md CHANGED
@@ -6,7 +6,7 @@ Garuda runs commands and edits files for a model, so we take security reports se
6
6
 
7
7
  | Version | Supported |
8
8
  | --- | --- |
9
- | 0.17.x | Yes |
9
+ | 0.18.x | Yes |
10
10
  | Older | No |
11
11
 
12
12
  ## Node and dependencies
@@ -1,33 +1,33 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ chooseModel,
4
+ keepProviderKeys,
5
+ loadModelsConfig,
6
+ providerKeySource,
7
+ resolveModel
8
+ } from "./chunk-2FIV2VZP.js";
2
9
  import {
3
10
  Runtime,
4
11
  auditDirFor
5
- } from "./chunk-2DYMJMRQ.js";
12
+ } from "./chunk-NHWHG3SW.js";
13
+ import "./chunk-65NUEOI7.js";
6
14
  import "./chunk-G2AX7MGS.js";
7
15
  import "./chunk-A2QAIRQL.js";
8
16
  import {
9
17
  FileSessionStore
10
- } from "./chunk-735BKABA.js";
11
- import {
12
- chooseModel,
13
- keepProviderKeys,
14
- loadModelsConfig,
15
- providerKeySource,
16
- resolveModel
17
- } from "./chunk-JRVWH27M.js";
18
- import "./chunk-U65DQZDB.js";
19
- import "./chunk-J4346IDH.js";
18
+ } from "./chunk-UKIE4AAM.js";
19
+ import "./chunk-7KBOIPUT.js";
20
20
  import {
21
21
  loadSearchConfig
22
22
  } from "./chunk-B25VL4RU.js";
23
23
  import "./chunk-23FXBNBB.js";
24
24
  import {
25
25
  VERSION
26
- } from "./chunk-BSK5T2ZG.js";
26
+ } from "./chunk-C57GHLKP.js";
27
27
  import "./chunk-5DEWP3YX.js";
28
- import "./chunk-ZAE25JM2.js";
29
- import "./chunk-ATW7BNIG.js";
30
28
  import "./chunk-PZS3V6P3.js";
29
+ import "./chunk-QANRZW7W.js";
30
+ import "./chunk-ATW7BNIG.js";
31
31
  import "./chunk-AOGFYUKG.js";
32
32
  import "./chunk-B4SJY7KT.js";
33
33
  import "./chunk-BHZ6G65V.js";
@@ -47,7 +47,7 @@ async function acpCommand(options) {
47
47
  `);
48
48
  return 1;
49
49
  }
50
- const { setupCommand, terminalIO } = await import("./setupCommand-GBQIVYJC.js");
50
+ const { setupCommand, terminalIO } = await import("./setupCommand-YMF6I3MD.js");
51
51
  return setupCommand({}, { io: await terminalIO() });
52
52
  }
53
53
  const output = protocolOutput(process.stdout, process.stderr);
@@ -190,4 +190,4 @@ export {
190
190
  prepare,
191
191
  protocolOutput
192
192
  };
193
- //# sourceMappingURL=acpCommand-7EY3NHPG.js.map
193
+ //# sourceMappingURL=acpCommand-IUZPLPLI.js.map
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  writeFileAtomic
4
- } from "./chunk-U65DQZDB.js";
4
+ } from "./chunk-65NUEOI7.js";
5
5
  import {
6
6
  keepSecretForRedaction,
7
7
  lookupModel
8
- } from "./chunk-J4346IDH.js";
8
+ } from "./chunk-7KBOIPUT.js";
9
9
  import {
10
10
  isLoopbackHost
11
11
  } from "./chunk-ATW7BNIG.js";
@@ -228,6 +228,9 @@ async function keepProviderKeys(names, home) {
228
228
  }
229
229
  return stored.warning;
230
230
  }
231
+ function providerKeyValue(name) {
232
+ return providerKey(process.env, name);
233
+ }
231
234
  function providerKey(env, name) {
232
235
  if (name === void 0) return void 0;
233
236
  return keptKeys.get(name)?.value ?? env[name];
@@ -326,6 +329,7 @@ export {
326
329
  setDefaultModel,
327
330
  providerKeySource,
328
331
  keepProviderKeys,
332
+ providerKeyValue,
329
333
  resolveModel
330
334
  };
331
- //# sourceMappingURL=chunk-JRVWH27M.js.map
335
+ //# sourceMappingURL=chunk-2FIV2VZP.js.map
@@ -6,10 +6,10 @@ import {
6
6
  import {
7
7
  gateProjectSettings,
8
8
  isCostIncomplete
9
- } from "./chunk-735BKABA.js";
9
+ } from "./chunk-UKIE4AAM.js";
10
10
  import {
11
11
  totalTokens
12
- } from "./chunk-J4346IDH.js";
12
+ } from "./chunk-7KBOIPUT.js";
13
13
  import {
14
14
  TrustStore
15
15
  } from "./chunk-5DEWP3YX.js";
@@ -350,4 +350,4 @@ export {
350
350
  msUntil,
351
351
  finishJob
352
352
  };
353
- //# sourceMappingURL=chunk-TJIWD7R7.js.map
353
+ //# sourceMappingURL=chunk-4BVCYCQT.js.map
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  knownModels
4
- } from "./chunk-J4346IDH.js";
4
+ } from "./chunk-7KBOIPUT.js";
5
5
 
6
6
  // src/model/catalog.ts
7
7
  import { mkdir, readFile, writeFile } from "fs/promises";
@@ -140,4 +140,4 @@ export {
140
140
  loadCatalog,
141
141
  mergedModels
142
142
  };
143
- //# sourceMappingURL=chunk-U65DQZDB.js.map
143
+ //# sourceMappingURL=chunk-65NUEOI7.js.map
@@ -146,6 +146,7 @@ export {
146
146
  knownModels,
147
147
  lookupModel,
148
148
  WEB_SEARCH_USD,
149
+ costOf,
149
150
  responseCost,
150
151
  totalTokens,
151
152
  contextSize,
@@ -153,4 +154,4 @@ export {
153
154
  keepSecretForRedaction,
154
155
  Redactor
155
156
  };
156
- //# sourceMappingURL=chunk-J4346IDH.js.map
157
+ //# sourceMappingURL=chunk-7KBOIPUT.js.map
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/version.ts
4
+ var VERSION = "0.18.0";
5
+
6
+ export {
7
+ VERSION
8
+ };
9
+ //# sourceMappingURL=chunk-C57GHLKP.js.map