@garuda-agent/garuda 0.16.1 → 0.17.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.
- package/CHANGELOG.md +182 -0
- package/README.md +56 -1074
- package/SECURITY.md +9 -2
- package/dist/{acpCommand-OTAYW7BS.js → acpCommand-7EY3NHPG.js} +18 -16
- package/dist/{anthropic-NQDBCHJU.js → anthropic-NQIZLD64.js} +12 -6
- package/dist/{chunk-TILFPYWO.js → chunk-2DYMJMRQ.js} +1880 -982
- package/dist/{chunk-YQTGMCU6.js → chunk-3MRQJKUO.js} +29 -5
- package/dist/{chunk-WMOLXTBU.js → chunk-4LFJFDCF.js} +2 -1
- package/dist/{chunk-44QN5SWZ.js → chunk-55CFEEIN.js} +22 -2
- package/dist/{chunk-USCUXCAU.js → chunk-5B5HDTUR.js} +3 -3
- package/dist/{chunk-TUUEBHG2.js → chunk-6XHON3Q6.js} +2 -2
- package/dist/chunk-735BKABA.js +472 -0
- package/dist/{chunk-B6FA4I7Q.js → chunk-7TH3NHCQ.js} +2 -2
- package/dist/{chunk-OUCV3FCT.js → chunk-AOGFYUKG.js} +3 -3
- package/dist/{chunk-GXZACJUI.js → chunk-B4SJY7KT.js} +322 -39
- package/dist/{chunk-3EQU2GUX.js → chunk-BHZ6G65V.js} +5 -1
- package/dist/chunk-BSK5T2ZG.js +9 -0
- package/dist/chunk-J4346IDH.js +156 -0
- package/dist/{chunk-NP6RIC25.js → chunk-JRVWH27M.js} +7 -7
- package/dist/{chunk-HUIK3WXO.js → chunk-P6XWWIEK.js} +20 -3
- package/dist/{chunk-HE2K657U.js → chunk-TJIWD7R7.js} +47 -16
- package/dist/chunk-U65DQZDB.js +143 -0
- package/dist/chunk-UIRJOQQS.js +118 -0
- package/dist/{chunk-KKB5W47S.js → chunk-VTMD5IHD.js} +26 -2
- package/dist/{chunk-BQTUOO4G.js → chunk-Z66BWTMD.js} +81 -32
- package/dist/cli/index.js +99 -41
- package/dist/{create-VXIH2GUZ.js → create-W6BV75QX.js} +18 -12
- package/dist/{deadline-F5RJJ2QW.js → deadline-TP7ZGLT2.js} +4 -2
- package/dist/{evalCommand-RGMZRYDR.js → evalCommand-YVQAWUZE.js} +50 -29
- package/dist/{export-HN3CT7AV.js → export-SJ3DUP6W.js} +2 -2
- package/dist/{inkChat-WEDGQMCY.js → inkChat-FNUBK43U.js} +14 -13
- package/dist/install-TKWN5AYH.js +19 -0
- package/dist/{job-3NYDMP2M.js → job-7JOI4YIQ.js} +6 -2
- package/dist/jobCommand-FE6XN3YD.js +33 -0
- package/dist/{launchd-SSX362VG.js → launchd-3A3ONEW5.js} +9 -8
- package/dist/{lspCommand-JRXKRSL7.js → lspCommand-ZZ6R4PA2.js} +7 -6
- package/dist/{manager-773PUDFE.js → manager-73MPYFTP.js} +7 -6
- package/dist/{nightCommand-65MUEV32.js → nightCommand-OODJNWDT.js} +26 -20
- package/dist/{openaiCompatible-CJWVJP5M.js → openaiCompatible-6TLDDW5U.js} +29 -15
- package/dist/{policy-EJPLEEXP.js → policy-ZJ7RMOFN.js} +10 -4
- package/dist/{remove-6GDSTAIO.js → remove-42WQNVPX.js} +8 -7
- package/dist/{server-NGKVIQEV.js → server-VEYIJHEU.js} +2 -2
- package/dist/{setupCommand-VA7D5MZK.js → setupCommand-GBQIVYJC.js} +45 -13
- package/dist/text-LS35WSRL.js +17 -0
- package/native/bin/garuda-reap +0 -0
- package/native/garuda-reap.c +113 -0
- package/package.json +39 -13
- package/dist/chunk-EIXUSVFX.js +0 -116
- package/dist/chunk-R7I2NBPX.js +0 -71
- package/dist/chunk-ULAJPMY7.js +0 -107
- package/dist/chunk-VBZCNMUD.js +0 -9
- package/dist/install-EWDSPFFZ.js +0 -18
- package/dist/jobCommand-ACSGSBQ4.js +0 -32
- package/dist/text-J2GD647J.js +0 -11
package/README.md
CHANGED
|
@@ -4,76 +4,34 @@
|
|
|
4
4
|
|
|
5
5
|
Website and docs: https://madhu-sv.github.io/garuda/
|
|
6
6
|
|
|
7
|
-
Garuda is a
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
| 0.14: sandbox launch probe, core modularization, background daemons (opt-in), interactive patch staging (W4) | Done (0.14.0) |
|
|
36
|
-
| 0.15: multi-language AST code intelligence (Python, Java, TS/JS, call graph, blast radius, /callers, /defs, /impact, ast_query) | Done (0.14.0) |
|
|
37
|
-
| 0.16: language plugins (Go and Rust built in, user plugins in ~/.garuda/languages, /languages; project plugins not loaded) | Done (0.14.0) |
|
|
38
|
-
| 0.17: Mixture-of-Experts subagents (opt-in), team policy and audit log (W5) | Done (0.14.0) |
|
|
39
|
-
| Editors over the Agent Client Protocol (`garuda acp`: VS Code with an extension, Zed, JetBrains, Neovim, Emacs) | Done (0.15.0) |
|
|
40
|
-
| `garuda setup` (model and stored key) and the editor sign-in (ACP Terminal Auth) | Done (0.16.0) |
|
|
41
|
-
|
|
42
|
-
The rows labelled 0.14–0.17 are branch labels, not versions: the "0.15" and "0.16" branches (code
|
|
43
|
-
intelligence, language plugins) shipped in 0.14.0. The last two rows are versions 0.15.0 and 0.16.0.
|
|
44
|
-
|
|
45
|
-
The 0.14–0.17 rows were built on stacked branches that were never released. They ship together as
|
|
46
|
-
0.14.0 after the merge gate: the high findings of the branch review are fixed (policy source, audit
|
|
47
|
-
log, hunk approval U0, daemons, MoE, project plugins), and features with no measured gain are off by
|
|
48
|
-
default (MoE, daemons). G02 to G08 are fixed too. The open gap G09 is listed in
|
|
49
|
-
[docs/quality-baseline/issue-register.md](docs/quality-baseline/issue-register.md). The section
|
|
50
|
-
headings below keep the branch labels (0.14–0.17).
|
|
51
|
-
|
|
52
|
-
Before 0.14.0, Garuda reviewed its own code with Fable 5.1, one area at a time (knowledge,
|
|
53
|
-
permissions, tools, sandbox, audit, loop, agents), in plan mode. 0.14.1 adds the cli and extensions
|
|
54
|
-
areas and fixes the open findings of all nine areas (see [CHANGELOG.md](CHANGELOG.md)). Known limits
|
|
55
|
-
in 0.16.1:
|
|
56
|
-
|
|
57
|
-
- G09: project language plugins are not loaded (no consent flow for their imports yet).
|
|
58
|
-
- Subagents: each child has its own step and token budget (capped by the team policy); it does not
|
|
59
|
-
take what the parent has left, and parallel `explore` calls each get one.
|
|
60
|
-
- Audit log: lines cut from the end of a file, or a removed file, are not detected (no anchor outside
|
|
61
|
-
the file).
|
|
62
|
-
- On macOS, secret-named variables other than the provider API keys stay in Garuda's own environment.
|
|
63
|
-
- Build tool caches that the sandbox may write (`~/.gradle/wrapper`, `jdks`, `native`, `caches`,
|
|
64
|
-
`~/.m2/wrapper`) hold programs that a build runs later outside the sandbox. They stay writable, because
|
|
65
|
-
`./gradlew` needs them in the sandbox; a sandboxed command could change them.
|
|
66
|
-
- The jdtls download is checked against the `.sha256` file of the same server, not a pinned hash.
|
|
67
|
-
- Editors (`garuda acp`): Garuda's session history is not in the editor (no `session/load`), the
|
|
68
|
-
editor's MCP servers are not started, Garuda reads saved files (not unsaved buffers), the terminal's
|
|
69
|
-
own commands (`/undo`, `/diff` …) are not available, and an edit is approved as a whole (no hunks).
|
|
70
|
-
- Stored keys are in a file (`~/.garuda/credentials`, mode 0600, hidden from the sandbox), not in the
|
|
71
|
-
OS keychain yet. Keep the file out of backups and dotfile sync.
|
|
72
|
-
- Native Windows is not supported; use WSL.
|
|
73
|
-
|
|
74
|
-
## Use
|
|
75
|
-
|
|
76
|
-
Install (0.14.1 and later) with Homebrew or npm. You need Node 22 or later; Homebrew installs it.
|
|
7
|
+
Garuda is a coding agent for the terminal, and for editors over the Agent Client Protocol. It reads
|
|
8
|
+
and edits your code, runs commands in an OS sandbox, and keeps an audit log of its permission
|
|
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).
|
|
11
|
+
|
|
12
|
+
## What Garuda does on your machine
|
|
13
|
+
|
|
14
|
+
- `read_file`, `glob` and `grep` run with no question.
|
|
15
|
+
- `write_file` and `edit_file` show a diff first. You allow once, allow for this session, or deny.
|
|
16
|
+
- Commands (`bash`) run in an OS sandbox when your machine has one: Seatbelt on macOS, bubblewrap
|
|
17
|
+
on Linux. There they run with no question, but they can write only in the project, temp folders
|
|
18
|
+
and package caches, cannot read secrets in your home folder (such as `~/.ssh`), and have no
|
|
19
|
+
network unless you open an allowlist. So a command can change project files without a question;
|
|
20
|
+
`/undo` restores the files in its snapshot (ignored files, such as build output, are not in it).
|
|
21
|
+
- A command outside the sandbox asks first, unless one of your allow rules covers it. The strict
|
|
22
|
+
profile forbids it. Without a sandbox, each command asks first, unless one of your allow rules
|
|
23
|
+
covers it.
|
|
24
|
+
- With staged commands (0.17, off by default), a sandboxed command
|
|
25
|
+
runs in a copy of the project, and its changes reach the project only after you apply them.
|
|
26
|
+
|
|
27
|
+
The details: [Sandbox, permissions and policy](docs/guide/safety.md). The known gaps:
|
|
28
|
+
[Status and known limits](docs/guide/status.md) and the
|
|
29
|
+
[issue register](docs/quality-baseline/issue-register.md).
|
|
30
|
+
|
|
31
|
+
## Install
|
|
32
|
+
|
|
33
|
+
You need Node 22.23.4, 24.22.1 or 26.12.1, or a later release of the same line: the latest security release of a supported line (Homebrew installs it). Garuda
|
|
34
|
+
warns at start on an older Node.
|
|
77
35
|
|
|
78
36
|
```sh
|
|
79
37
|
npm install -g @garuda-agent/garuda
|
|
@@ -88,19 +46,10 @@ brew trust --formula madhu-sv/garuda/garuda
|
|
|
88
46
|
brew install garuda
|
|
89
47
|
```
|
|
90
48
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
```sh
|
|
95
|
-
npm install -g pnpm@10
|
|
96
|
-
git clone https://github.com/madhu-sv/garuda.git && cd garuda
|
|
97
|
-
pnpm install
|
|
98
|
-
pnpm check # typecheck + lint + tests
|
|
99
|
-
pnpm build
|
|
100
|
-
pnpm link --global # optional: puts `garuda` on your PATH (run `pnpm setup` once first)
|
|
101
|
-
```
|
|
49
|
+
To build from source, see [CONTRIBUTING.md](CONTRIBUTING.md). Native Windows is not supported; use
|
|
50
|
+
WSL.
|
|
102
51
|
|
|
103
|
-
|
|
52
|
+
## Quick start
|
|
104
53
|
|
|
105
54
|
```sh
|
|
106
55
|
garuda setup # once: pick a provider and model, enter the key
|
|
@@ -109,1002 +58,35 @@ garuda -p "Explain what this repo does" # run one task and exit
|
|
|
109
58
|
echo "Explain this repo" | garuda # the same, from stdin
|
|
110
59
|
```
|
|
111
60
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
with one free request to the provider, and stores the model as `"default"` in
|
|
116
|
-
`~/.garuda/models.json` and the key in `~/.garuda/credentials` (mode 0600; commands in the sandbox
|
|
117
|
-
cannot read it). `garuda setup --show` shows the model and where each key comes from (masked);
|
|
118
|
-
`garuda setup --forget [NAME]` removes stored keys. Environment variables still work and win:
|
|
119
|
-
`ANTHROPIC_API_KEY`, `GARUDA_MODEL`. Do not sync or back up `~/.garuda/credentials` to other places.
|
|
120
|
-
|
|
121
|
-
Tools: read_file, glob and grep run with no question.
|
|
122
|
-
write_file, edit_file and bash show a diff or the command first. You pick: allow once, allow for this session, or deny.
|
|
123
|
-
Commands run in an OS sandbox when your machine has one (see Sandbox below). Without a sandbox,
|
|
124
|
-
each command asks first, so read each one before you allow it.
|
|
125
|
-
Garuda removes a leading `cd <working root> &&` from a command, because each command already starts there.
|
|
126
|
-
When the model reads files with bash, or pipes into head or tail, the result adds a short `[Garuda: …]` note that tells it to use the file tools.
|
|
127
|
-
|
|
128
|
-
For scripts and CI, `--output-format json` prints one JSON result, and `--output-format stream-json`
|
|
129
|
-
prints one JSON object per line as the task runs. The fields are those of Claude Code's headless mode
|
|
130
|
-
(`claude -p --output-format …`), so the same scripts work:
|
|
131
|
-
|
|
132
|
-
```sh
|
|
133
|
-
g -p "Run the tests" --output-format json | jq -r '.subtype, .total_cost_usd, .result'
|
|
134
|
-
g -p "Fix the lint errors" --output-format stream-json --verbose > run.jsonl
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
stdout holds only JSON; warnings and errors go to stderr (`--verbose` adds the tool activity). The exit
|
|
138
|
-
code does not change. Details: [docs/lld/cli.md](docs/lld/cli.md#json-output-jsonoutputts-05).
|
|
139
|
-
|
|
140
|
-
Try it on this repo:
|
|
141
|
-
|
|
142
|
-
```sh
|
|
143
|
-
node dist/cli/index.js -p "Where is runAgent defined, and what does it do?"
|
|
144
|
-
node dist/cli/index.js -p "Run the tests and tell me the result"
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
## Models
|
|
148
|
-
|
|
149
|
-
`-m` (or `GARUDA_MODEL`) takes a Claude model id, or `<provider>/<model>` for other providers:
|
|
150
|
-
|
|
151
|
-
```sh
|
|
152
|
-
g -m claude-sonnet-5 # Anthropic (ANTHROPIC_API_KEY)
|
|
153
|
-
g -m ollama/qwen3-coder:30b # Ollama on this machine
|
|
154
|
-
g -m lmstudio/<model> # LM Studio (also: llamacpp/…, vllm/…)
|
|
155
|
-
g -m openrouter/qwen/qwen3-coder # OpenRouter (OPENROUTER_API_KEY)
|
|
156
|
-
g eval -m ollama/qwen3-coder:30b -s hard # measure an open model on the eval tasks
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
Set the context window, price and output limit per model, and add providers, in `~/.garuda/models.json`:
|
|
160
|
-
|
|
161
|
-
```json
|
|
162
|
-
{
|
|
163
|
-
"providers": { "lab": { "type": "openai-compatible", "baseUrl": "https://llm.example.com/v1", "apiKeyEnv": "LAB_KEY" } },
|
|
164
|
-
"models": { "ollama/qwen3-coder:30b": { "contextWindow": 65536, "maxTokens": 8192 } },
|
|
165
|
-
"default": "ollama/qwen3-coder:30b"
|
|
166
|
-
}
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
- Only this file in your home folder can define providers; a project cannot send your code elsewhere.
|
|
170
|
-
Keys come from environment variables. Plain http works only to this machine (or with
|
|
171
|
-
`"allowInsecureHttp": true`).
|
|
172
|
-
- `"default"` is the model when neither `--model` nor `GARUDA_MODEL` names one.
|
|
173
|
-
- Some small models write a tool call as JSON text. When the whole reply is such a call to a known
|
|
174
|
-
tool, Garuda runs it as a real call, with the usual approvals. For a model that also writes
|
|
175
|
-
sentences around the call (for example `qwen2.5-coder:7b`), set `"textToolCalls": "lines"` for that
|
|
176
|
-
model: then a call on its own line runs too. A call in the middle of a sentence never runs.
|
|
177
|
-
- Without a `contextWindow`, Garuda assumes 32 768 tokens for open models and says so. The server must
|
|
178
|
-
allow the window too: for Ollama, start it with `OLLAMA_CONTEXT_LENGTH=65536 ollama serve`.
|
|
179
|
-
- Local models cost $0. Tool calling quality varies by model: measure a model with `g eval` first.
|
|
180
|
-
|
|
181
|
-
## Chat mode
|
|
182
|
-
|
|
183
|
-
`garuda` with no task starts a chat. Each line is one task; the conversation carries over.
|
|
184
|
-
|
|
185
|
-
- `/help`, `/usage` (tokens and cost), `/session` (id and file), `/new` (new session), `/commands`
|
|
186
|
-
(your custom commands), `/plan` and `/build` (plan mode), `/undo` and `/redo`, `/lsp` (language servers),
|
|
187
|
-
`/init` (set up this folder, see below), `/editor`, `/compact`, `/details`, `/thinking`, `/diff` (see Undo), `/schedule` and `/jobs` (see
|
|
188
|
-
Scheduled jobs), `/exit`. Your custom commands and
|
|
189
|
-
skills run with `/name`.
|
|
190
|
-
- `/sessions` lists this project's sessions (newest first: time, first prompt, turns, cost, model).
|
|
191
|
-
`/sessions <number or id>` continues one in the chat, as `--resume` does. Read tracking starts again.
|
|
192
|
-
`/sessions rename <number or id> <title>` gives a session a title for the list. `/sessions delete <number
|
|
193
|
-
or id>` asks, then deletes the session file and its subagent logs for good; the open session cannot go.
|
|
194
|
-
- `/models` lists the known Claude models and the models in `~/.garuda/models.json`, with context window and
|
|
195
|
-
price. `/models <number, id or opus|sonnet|haiku|fable>` switches the main model for the next turns of this
|
|
196
|
-
chat. The session records the change; a new chat starts with `-m` or `GARUDA_MODEL` again. The prompt cache
|
|
197
|
-
starts again; a smaller window makes Garuda compact the conversation first. Explore keeps the start model.
|
|
198
|
-
- `/export [file]` writes the conversation as Markdown in the working folder (default
|
|
199
|
-
`garuda-<session id>.md`): prompts and answers in full, one line per tool call. It comes from the session
|
|
200
|
-
file, so secrets are redacted. It never overwrites a file and never writes outside the folder.
|
|
201
|
-
- `/compact [what to keep]` summarises the older turns now, to free context before a new part of the
|
|
202
|
-
work. The last 4 steps stay in full. The optional text tells the summary what to keep, for example
|
|
203
|
-
`/compact keep the API decisions`. Esc stops it; the conversation then stays as it was. Garuda still
|
|
204
|
-
compacts on its own when the context gets full.
|
|
205
|
-
- `/details` hides the result line under each tool call (`⎿ 12 line(s)`), so a turn shows one line per
|
|
206
|
-
call. A failed call still shows its result, and Ctrl-O still shows the last output in full. `/details`
|
|
207
|
-
again, or `/details on`, shows them. It applies to new lines only.
|
|
208
|
-
- `/thinking` controls Claude's thinking for this chat. Claude Opus 5.5, Opus 5 and Sonnet 5 always think;
|
|
209
|
-
Opus 4.6 to 4.8 and Sonnet 4.6 think only after `/thinking on`. `/thinking low|medium|high|xhigh|max`
|
|
210
|
-
sets the effort (less or more thinking; `default` goes back). Garuda always asks for short summaries
|
|
211
|
-
of the thinking, so data keeps coming while the model thinks (with no data for 5 minutes, the
|
|
212
|
-
connection closed and a long answer was lost; Garuda now also waits up to 20 minutes for the next
|
|
213
|
-
data). By default they are hidden. `/thinking show` shows
|
|
214
|
-
them: the chat shows their first lines dimmed, and Ctrl-O shows all of it until the next tool output
|
|
215
|
-
replaces it; `hide` goes back. The session records the choice; `"thinking": { "effort": "low",
|
|
216
|
-
"show": true }` in settings sets the start value. A change of effort or on/off starts the prompt cache
|
|
217
|
-
again; show and hide do not. Other providers do not offer it.
|
|
218
|
-
- Esc or Ctrl-C during a task stops the task and kills its commands (Esc also drops queued lines). The
|
|
219
|
-
chat goes on, and the model learns with your next message that you stopped the task, so it does not
|
|
220
|
-
go on with it unless you ask. A second Ctrl-C during the task exits Garuda at once; Esc never exits.
|
|
221
|
-
- New lines: end the line with `\` and press Enter, or press Alt+Enter (Option+Enter on a Mac with
|
|
222
|
-
"Use Option as Meta"). Pasted text keeps its new lines and is never sent by itself.
|
|
223
|
-
- `@path` attaches a file or folder: `fix the bug in @src/cart.ts`. The file's text goes with your
|
|
224
|
-
message (numbered, up to 2,000 lines) and counts as read, so the model can edit it at once; a folder gives
|
|
225
|
-
its list of entries. The same rules as `read_file`: only files in the folder, no secrets (`.env`, keys),
|
|
226
|
-
and the same permission check (deny rules, the team policy's `denyPaths`, a link to a secret; 0.14).
|
|
227
|
-
Garuda shows what it attached. A word after `@` that is not a path stays text.
|
|
228
|
-
- `!command` runs a command yourself, like the bash tool: in the sandbox with no question, deny rules and
|
|
229
|
-
hooks apply. You see the output, and it goes to the model with your next message. Esc stops it.
|
|
230
|
-
- Tab completes `/commands` (built-in, your own, skills) and `@paths`; with several matches it lists them.
|
|
231
|
-
It also completes arguments: `/models <model>`, `/sessions <id|rename|delete>` (with each session's
|
|
232
|
-
title), `/jobs <id|cancel>`, `/diff last`, `/mcp logout <server>` and `/lsp install <language>`.
|
|
233
|
-
- When no path starts with what you typed after `@`, Tab searches all files by their letters in order:
|
|
234
|
-
`@rntm` finds `src/app/runtime.ts`. One match completes; otherwise the best 10 are listed. The search
|
|
235
|
-
skips hidden files, `node_modules`, `dist`, `build`, `target` and virtual environments.
|
|
236
|
-
- Ctrl-P opens the command palette (full chat only): every command with its one-line help, then your
|
|
237
|
-
own commands and skills. Type to filter: `thk` finds `/thinking`; when no name matches, words of the
|
|
238
|
-
help do (`markdown` finds `/export`). ↑/↓ choose. Enter runs a command that needs no arguments (`/usage`, `/undo`, `/details` …) or puts
|
|
239
|
-
`/name ` in the input line for one that takes them (`/models`, `/sessions`, `/thinking` …), so Tab can
|
|
240
|
-
complete the rest. Esc or Ctrl-P closes it.
|
|
241
|
-
- Ctrl-G (or `/editor`) opens the prompt in `$VISUAL` or `$EDITOR` (default `vi`). The saved text comes
|
|
242
|
-
back into the input line; press Enter to send it. The plain chat also joins lines that end with `\`.
|
|
243
|
-
- At the prompt, Ctrl-C clears the line; Ctrl-C twice (within 2 s) or Ctrl-D exits.
|
|
244
|
-
- On a terminal, the chat uses Ink (0.2): model text streams, and each finished paragraph gets
|
|
245
|
-
basic markdown styles. A spinner shows running tools. The footer shows the model, the sandbox,
|
|
246
|
-
the context use and the cost.
|
|
247
|
-
- Type-ahead: type during a task and press Enter to queue the next task.
|
|
248
|
-
Keys typed before the chat is ready are kept too.
|
|
249
|
-
- Ctrl-O prints the full output of the last tool call. ↑ and ↓ browse earlier inputs.
|
|
250
|
-
- Approvals show the full diff or command in the scrollback. Answer with ↑↓ and Enter, or
|
|
251
|
-
y (once), a (session), n or Esc (deny). For `edit_file`, press `h` (or `p`) to review hunks one by one (0.14): only the hunks you stage
|
|
252
|
-
are written, and the model is told which ones you rejected. A diff too long to show in full has no `h`.
|
|
253
|
-
- `GARUDA_PLAIN=1` turns Ink off. Pipes, `-p`, the evals and the standalone binary always use plain output.
|
|
254
|
-
- Notifications: when an approval waits during a task, and when a task that ran 10 s or longer ends, Garuda
|
|
255
|
-
tells you. In iTerm2, Ghostty and WezTerm it sends a desktop notification (the OSC 9 escape code); in other
|
|
256
|
-
terminals and in tmux it rings the bell. `GARUDA_NOTIFY=off|bell|osc9|auto`, or
|
|
257
|
-
`"notifications": { "channel": "off", "afterSeconds": 30 }` in `.garuda/settings.json`, changes it.
|
|
258
|
-
In iTerm2 the notification needs "Send escape sequence-generated alerts" (Settings › Profiles › Terminal),
|
|
259
|
-
which is on by default.
|
|
260
|
-
In iTerm2, Ghostty, WezTerm and the VS Code terminal, the full chat turns on focus reporting: while
|
|
261
|
-
Garuda's window has focus, no notification goes out. In other terminals, in tmux and in the plain chat,
|
|
262
|
-
every notification goes.
|
|
263
|
-
- Files are written atomically (a temporary file, then a rename), so an exit never leaves half a file.
|
|
264
|
-
- `garuda --resume` continues the latest session in chat mode.
|
|
265
|
-
|
|
266
|
-
Model text goes to stdout; tool activity and notes go to stderr. So `garuda -p "…" > answer.md` keeps only the answer.
|
|
267
|
-
|
|
268
|
-
## Editors (ACP, 0.15; sign-in 0.16)
|
|
269
|
-
|
|
270
|
-
`garuda acp` runs Garuda as an agent for editors that speak the Agent Client Protocol. The editor
|
|
271
|
-
starts it, shows the conversation, the tool calls and the questions, and Garuda does the work with
|
|
272
|
-
the same permission engine, OS sandbox, team policy, hooks and audit log as in the terminal.
|
|
273
|
-
|
|
274
|
-
Run `garuda setup` once in a terminal (see Use): then the editor needs no key in its settings.
|
|
275
|
-
|
|
276
|
-
VS Code, with the extension "ACP Client" (`formulahendry.acp-client`), in the user settings
|
|
277
|
-
(Cmd+Shift+P, **Preferences: Open User Settings (JSON)**). Use the full path from `which garuda`:
|
|
278
|
-
VS Code started from the Dock does not get your shell's `PATH`.
|
|
279
|
-
|
|
280
|
-
```json
|
|
281
|
-
{
|
|
282
|
-
"acp.agents": {
|
|
283
|
-
"Garuda": { "command": "/opt/homebrew/bin/garuda", "args": ["acp"] }
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
```
|
|
287
|
-
|
|
288
|
-
Zed: the same command and argument under `agent_servers` (with `"type": "custom"`). With no model
|
|
289
|
-
or key, Zed offers **Set up Garuda** (ACP Terminal Auth, 0.16): it runs `garuda acp setup` in a
|
|
290
|
-
terminal, and the next thread works. The website's
|
|
291
|
-
[Editors](https://madhu-sv.github.io/garuda/docs/editors/) page has the steps and what the editor
|
|
292
|
-
shows.
|
|
293
|
-
|
|
294
|
-
- Each edit asks in the editor, with the editor's diff view; "Allow for this session" lasts for this
|
|
295
|
-
session only. Keep an extension's auto-approve off: it answers Garuda's questions for you.
|
|
296
|
-
- The editor's stop button ends the turn: a running command stops, and a waiting question is a deny.
|
|
297
|
-
Each call that the stop ended shows as failed, with a line such as "Garuda: $ sleep 60 cancelled."
|
|
298
|
-
A command that exits with an error shows as done (the model reads the error); a refused call shows
|
|
299
|
-
as failed.
|
|
300
|
-
- Build and plan modes are in the editor's mode menu; custom commands and skills are in its `/` menu.
|
|
301
|
-
Built-in chat commands (`/undo`, `/diff` ...) are only in the terminal in this version.
|
|
302
|
-
- Garuda reads and writes files and runs commands itself; it does not use the editor's file or
|
|
303
|
-
terminal access, so it reads the saved file, not an unsaved buffer. It does not start MCP servers
|
|
304
|
-
that the editor sends (its own `~/.garuda/mcp.json` and the project's work as usual).
|
|
305
|
-
- Project settings that loosen safety apply only after a yes in a terminal (`garuda` in that folder).
|
|
306
|
-
|
|
307
|
-
Design: [docs/lld/acp.md](docs/lld/acp.md).
|
|
308
|
-
|
|
309
|
-
## Init: set up a folder
|
|
310
|
-
|
|
311
|
-
`garuda init` (or `/init` in the chat) sets up the current folder:
|
|
312
|
-
|
|
313
|
-
1. It reads the files of other coding agents: Claude Code, OpenCode, Codex, Gemini CLI, Tabnine, Cursor
|
|
314
|
-
and Copilot. It shows what goes where (MCP servers, slash commands, permission rules), then asks once.
|
|
315
|
-
It writes **new files only**: an existing `mcp.json`, `settings.json` or command file is never changed.
|
|
316
|
-
It adds Garuda's local folders to `.gitignore`. Secret values (tokens, keys) are never copied; they
|
|
317
|
-
become `${NAME}`, so set them in your environment.
|
|
318
|
-
2. If the folder is not a git repository, it offers `git init`.
|
|
319
|
-
3. In a code project, the model reads the code and writes or improves `AGENTS.md` (build and test
|
|
320
|
-
commands, structure, conventions). It also reads other agents' instruction files (`GEMINI.md`,
|
|
321
|
-
`.cursorrules`, `.github/copilot-instructions.md` …) and carries over what applies. In an empty folder,
|
|
322
|
-
it asks what you want to build first.
|
|
323
|
-
|
|
324
|
-
When a folder has no `AGENTS.md`, or has another agent's files, the chat start shows a hint to type `/init`.
|
|
325
|
-
Imported project servers and commands still ask for consent the first time. Details: [docs/lld/init.md](docs/lld/init.md).
|
|
326
|
-
|
|
327
|
-
## Custom slash commands
|
|
328
|
-
|
|
329
|
-
Save a prompt as a Markdown file and run it with `/name`:
|
|
330
|
-
|
|
331
|
-
```markdown
|
|
332
|
-
<!-- ~/.garuda/commands/review.md (yours) or .garuda/commands/review.md (the project's) -->
|
|
333
|
-
---
|
|
334
|
-
description: Review a file for bugs
|
|
335
|
-
argument-hint: <path>
|
|
336
|
-
---
|
|
337
|
-
Review $1 for bugs and missing tests. List the problems by severity.
|
|
338
|
-
```
|
|
339
|
-
|
|
340
|
-
- `/review src/cart.ts` in the chat, or `garuda -p "/review src/cart.ts"`. `$ARGUMENTS` takes all
|
|
341
|
-
arguments, `$1` … `$9` one each. `/commands` lists them; `/help` shows them too.
|
|
342
|
-
- A subfolder gives a name with a colon: `frontend/test.md` → `/frontend:test`.
|
|
343
|
-
- A command is only a prompt. Its tool calls ask or run in the sandbox as usual.
|
|
344
|
-
- A project command shows its full text and asks the first time. "Remember" pins the answer to the
|
|
345
|
-
file; a changed file asks again. Built-in commands, and your own commands, win over project commands
|
|
346
|
-
with the same name.
|
|
347
|
-
|
|
348
|
-
## Skills
|
|
349
|
-
|
|
350
|
-
A skill is a folder with a `SKILL.md`: instructions for one kind of task, in the
|
|
351
|
-
[Agent Skills](https://agentskills.io/specification) format that Claude Code uses. Garuda reads your
|
|
352
|
-
Claude Code skills where they are.
|
|
353
|
-
|
|
354
|
-
```markdown
|
|
355
|
-
<!-- ~/.garuda/skills/release-notes/SKILL.md (or ~/.claude/skills, .garuda/skills, .claude/skills) -->
|
|
356
|
-
---
|
|
357
|
-
name: release-notes
|
|
358
|
-
description: Write release notes from the git log. Use when the user asks for release notes or a changelog.
|
|
359
|
-
---
|
|
360
|
-
Read `git log --oneline $0..HEAD`. Group the changes into Added, Changed and Fixed. Follow
|
|
361
|
-
references/style.md in this folder.
|
|
362
|
-
```
|
|
363
|
-
|
|
364
|
-
- The model sees each skill's name and description. When a task matches, it loads the skill with the
|
|
365
|
-
`skill` tool, and reads the skill's other files (`references/`, `scripts/`) only when it needs them.
|
|
366
|
-
- Run one yourself: `/release-notes v0.4.0`. `$ARGUMENTS`, `$0`, `$1` … and `${CLAUDE_SKILL_DIR}` work as in
|
|
367
|
-
Claude Code. A skill wins over a custom command with the same name. `/commands` lists them.
|
|
368
|
-
- A project skill shows its full text and asks the first time it loads. "Remember" pins the answer to
|
|
369
|
-
SKILL.md; a changed file asks again. Your own skills win over project skills with the same name.
|
|
370
|
-
- `disable-model-invocation: true`: only you can run it. `user-invocable: false`: only the model can.
|
|
371
|
-
`allowed-tools` is ignored: every call still asks or runs in the sandbox.
|
|
372
|
-
- Nothing changes when you have no skills. `"skills": { "enabled": false }` in `.garuda/settings.json`
|
|
373
|
-
turns them off. Details: [docs/lld/skills.md](docs/lld/skills.md).
|
|
374
|
-
|
|
375
|
-
## Plan mode
|
|
376
|
-
|
|
377
|
-
In plan mode the agent reads the code and writes a plan; it cannot change anything.
|
|
378
|
-
|
|
379
|
-
- `/plan` and `/build` switch the mode; in the chat, Shift+Tab toggles it. `garuda --plan` starts in plan
|
|
380
|
-
mode. The footer shows `PLAN`. `/plan <task>` switches and plans the task at once (`/build <task>` too).
|
|
381
|
-
- Allowed: reading tools, and bash in the sandbox, which then cannot write the project (temp folders and
|
|
382
|
-
package caches only), so read-only commands and many tests still work. Denied, with no question: file
|
|
383
|
-
edits and writes, `remember`, commands outside the sandbox, and web_fetch or MCP tools without an allow
|
|
384
|
-
rule. With no OS sandbox, bash is off in plan mode.
|
|
385
|
-
- When the plan is ready, Garuda asks "Build this plan?": build it now, switch to build mode and type the
|
|
386
|
-
task yourself, or keep planning.
|
|
387
|
-
|
|
388
|
-
## Undo
|
|
389
|
-
|
|
390
|
-
Before each turn, Garuda takes a snapshot of the project. `/undo` takes back the last turn: its file
|
|
391
|
-
changes (edits, new and deleted files, and files that commands changed) and its messages, so the model
|
|
392
|
-
forgets it. `/redo` brings it back.
|
|
393
|
-
|
|
394
|
-
- It asks first, with the list of files. Changes that you made after the turn go back too.
|
|
395
|
-
- Snapshots are in `~/.garuda/snapshots`, in a git store of Garuda's own. Your repository, index and
|
|
396
|
-
branches do not change, and the project does not need git. `.gitignore` rules apply.
|
|
397
|
-
- It works after `garuda --resume`. After the conversation was compacted, undo restores only the files.
|
|
398
|
-
- Cost: about 15–90 ms per turn. `"undo": { "enabled": false }` in `.garuda/settings.json` turns it off.
|
|
399
|
-
- `/diff` shows what changed since the first turn of this session: the files with `+`/`−` line counts, then
|
|
400
|
-
the diff (300 lines; Ctrl-O shows all). `/diff last` shows only the last turn; `/diff <path>` or
|
|
401
|
-
`/diff last <path>` limits it to one file or folder. It compares with the files now, so your own changes
|
|
402
|
-
count too. It uses the undo snapshots, so it is off when undo is off.
|
|
403
|
-
|
|
404
|
-
## Formatters (opt-in)
|
|
405
|
-
|
|
406
|
-
With `"formatters": { "enabled": true }` in `.garuda/settings.json`, Garuda runs the project's own
|
|
407
|
-
formatter on each file that `edit_file` or `write_file` changes, and the result shows what it changed:
|
|
408
|
-
|
|
409
|
-
```
|
|
410
|
-
Edited src/cart.ts.
|
|
411
|
-
Formatted with prettier:
|
|
412
|
-
- const total=items.reduce((s,i)=>s+i.price,0)
|
|
413
|
-
+ const total = items.reduce((s, i) => s + i.price, 0);
|
|
414
|
-
```
|
|
415
|
-
|
|
416
|
-
- It finds Biome or Prettier (their config and `node_modules/.bin`), ruff or black (`pyproject.toml`,
|
|
417
|
-
a venv or PATH), gofmt (`go.mod`) and rustfmt (`Cargo.toml`). It never installs a formatter.
|
|
418
|
-
- `"commands"` changes the list: `{ "prettier": false }` turns one off; `{ "mine": { "extensions":
|
|
419
|
-
["txt"], "command": ["fmt", "$FILE"] } }` adds one or replaces a detected one.
|
|
420
|
-
- Formatters run only in the OS sandbox, like the model's commands. A failed formatter adds a note; it
|
|
421
|
-
never undoes the edit.
|
|
422
|
-
- Off by default until measured: `garuda eval -s hard --repeat 3 --format on` (and `--format off`).
|
|
423
|
-
|
|
424
|
-
## LSP diagnostics (opt-in)
|
|
425
|
-
|
|
426
|
-
With `garuda --lsp`, or `"lsp": { "enabled": true }` in `.garuda/settings.json`, a language server checks
|
|
427
|
-
each file that `edit_file` or `write_file` changes, and the result lists its errors:
|
|
428
|
-
|
|
429
|
-
```
|
|
430
|
-
Edited src/cart.ts.
|
|
431
|
-
|
|
432
|
-
1 error in src/cart.ts after this change (tsc):
|
|
433
|
-
14:7 Type 'string' is not assignable to type 'number'. [2322]
|
|
434
|
-
```
|
|
435
|
-
|
|
436
|
-
- TS/JS: TypeScript 7 (`tsc --lsp`), `tsgo` or `typescript-language-server`. Python: basedpyright or
|
|
437
|
-
pyright. Java: jdtls (it needs Java 21 or later; `JAVA_HOME` or a usual JDK folder). For a Maven or
|
|
438
|
-
Gradle project, jdtls starts with the first task, because its project import takes a while.
|
|
439
|
-
- Garuda uses a server on your PATH (for Java also `brew install jdtls`), or its own copy:
|
|
440
|
-
`garuda lsp install typescript` (or `python`, `java`) installs a pinned version into `~/.garuda/lsp/`. With `{ "autoInstall": true }` in
|
|
441
|
-
`~/.garuda/lsp.json`, Garuda asks to install a missing server at the first edit.
|
|
442
|
-
- `garuda lsp` (or `/lsp` in the chat) shows the servers and their state.
|
|
443
|
-
- Servers run only in the OS sandbox: the project is read-only for them, and they have no network. A
|
|
444
|
-
missing, slow or broken server never blocks an edit.
|
|
445
|
-
- Off by default: in the A/B eval on the hard suite the model made no type errors, so LSP had nothing to
|
|
446
|
-
catch. Measure it again with `garuda eval -s hard --repeat 3 --lsp on`.
|
|
447
|
-
|
|
448
|
-
## Todo list (opt-in)
|
|
449
|
-
|
|
450
|
-
`"todo": { "enabled": true }` in `.garuda/settings.json` gives the model a `todo_write` tool: for a task
|
|
451
|
-
with 3 or more steps it keeps a plan, and the chat shows it as a checklist (`✔`, `▶`, `○`). It is off by
|
|
452
|
-
default: in the A/B eval on the hard suite the model never called it. Measure it again with
|
|
453
|
-
`garuda eval -s hard --repeat 3 --todo on`.
|
|
454
|
-
|
|
455
|
-
## Evals
|
|
456
|
-
|
|
457
|
-
`garuda eval` runs eval tasks in scratch folders and reports pass or fail, steps, tokens and cost per task (N5).
|
|
458
|
-
A task passes when its check command exits with 0 and the agent did not change the task's tests.
|
|
459
|
-
The 0.1 target is 7 of 10.
|
|
460
|
-
|
|
461
|
-
```sh
|
|
462
|
-
garuda eval --list # the tasks of each suite
|
|
463
|
-
garuda eval -m claude-sonnet-5 # the basic suite (10 small repos)
|
|
464
|
-
garuda eval -s hard # the hard suite (6 tasks on a 110-file repo)
|
|
465
|
-
garuda eval -t fix-add hard-rename --keep # some tasks, keep the scratch folders
|
|
466
|
-
garuda eval -s hard --repeat 3 # each task 3 times, with a mean row per task
|
|
467
|
-
garuda eval -s hard --repeat 3 --index lookup # the same, with find_symbol and find_references (A/B)
|
|
468
|
-
garuda eval -s java # 5 Maven projects with JUnit 5
|
|
469
|
-
garuda eval -s python # 5 pytest projects
|
|
470
|
-
garuda eval -s hard --repeat 3 --subagents on # A/B: the same, with the explore subagent
|
|
471
|
-
garuda eval --parallel 4 # 4 tasks at the same time
|
|
472
|
-
garuda eval --batch on # A/B: model calls through the Batch API (half price, slow)
|
|
473
|
-
garuda eval -s hard --keep-thinking off # A/B: drop Claude's thinking blocks, as before 0.9
|
|
474
|
-
garuda eval -s hard --format on # A/B: Biome formats after each edit (and --format off)
|
|
475
|
-
```
|
|
476
|
-
|
|
477
|
-
`--batch on` (0.7, Anthropic models) sends every model call as a batch of one: half the token price,
|
|
478
|
-
but each step waits until its batch ends (usually minutes). It runs all tasks at the same time (up to 20;
|
|
479
|
-
`--parallel` changes it) and gives each task 12 hours. The report shows the share of tokens from the
|
|
480
|
-
prompt cache and the wall time, to compare with `--batch off`.
|
|
481
|
-
|
|
482
|
-
The Java and Python suites need a toolchain. `garuda eval` checks it before the first model call and
|
|
483
|
-
says what is missing:
|
|
484
|
-
|
|
485
|
-
- Java: a JDK (17 or later), Maven, and JUnit 5 in `~/.m2`. Run `garuda eval --prepare java` once: it
|
|
486
|
-
runs Maven on a small project with network, to download the plugins and JUnit. The evals then run
|
|
487
|
-
offline.
|
|
488
|
-
- Python: `python3` with pytest 7 or later (`python3 -m pip install --user pytest`).
|
|
489
|
-
`garuda eval --prepare python` checks it.
|
|
490
|
-
|
|
491
|
-
The checks guard against shortcuts: the tests and build files (`pom.xml`, `pyproject.toml`) are
|
|
492
|
-
protected, the Java check refuses a `.mvn` folder, and pytest reads only `pyproject.toml` and no
|
|
493
|
-
`conftest.py`.
|
|
494
|
-
|
|
495
|
-
### Benchmark your repo (0.12)
|
|
496
|
-
|
|
497
|
-
Measure Garuda on your own code. `--from-git` turns recent commits that changed code and tests into
|
|
498
|
-
tasks: the agent starts at the commit's parent, gets the commit message and the commit's tests, and
|
|
499
|
-
passes when the tests pass and it did not change them.
|
|
500
|
-
|
|
501
|
-
```sh
|
|
502
|
-
garuda eval --from-git # build .garuda/evals/repo-suite.json from the last 200 commits
|
|
503
|
-
garuda eval --from-git --since 2026-01-01 --max-tasks 10 --test-command "pnpm test"
|
|
504
|
-
garuda eval -s repo --list # the tasks
|
|
505
|
-
garuda eval -s repo -m claude-sonnet-5 # run them (the A/B flags work too)
|
|
506
|
-
```
|
|
507
|
-
|
|
508
|
-
A commit is kept only when its tests fail at the parent and pass at the commit. Garuda runs only the
|
|
509
|
-
commit's test files when it knows the runner; `--test-command "make test T={files}"` works for others.
|
|
510
|
-
Commits that change dependencies, binary files or more than 10 code files are skipped. Building runs your test command twice per
|
|
511
|
-
candidate on this machine, with no sandbox, in git worktrees: your checkout does not change.
|
|
512
|
-
|
|
513
|
-
The runner approves every call except its deny rules (`rm -rf`, `sudo`, `git push`, `curl`, `wget`).
|
|
514
|
-
Commands, and the check after each task, run in the scratch folders, in the OS sandbox when there is one (`--executor auto|os|host`). Results and session files go to
|
|
515
|
-
`.garuda/evals/<run-id>/`.
|
|
516
|
-
|
|
517
|
-
`pnpm startup` checks that startup takes less than 1 s (N3). The Anthropic SDK and the prompt library
|
|
518
|
-
load on first use, not at startup.
|
|
519
|
-
|
|
520
|
-
## Code index and dynamic language plugins (local knowledge)
|
|
521
|
-
|
|
522
|
-
Garuda keeps a local code index with a dynamic language plugin architecture (0.16).
|
|
523
|
-
It answers code questions on this machine, with zero native C++ compilation dependencies and no model call:
|
|
61
|
+
`garuda setup` stores the model in `~/.garuda/models.json` and the key in `~/.garuda/credentials`
|
|
62
|
+
(mode 0600; commands in the sandbox cannot read it). `ANTHROPIC_API_KEY` and `GARUDA_MODEL` in the
|
|
63
|
+
environment still work and win.
|
|
524
64
|
|
|
525
|
-
|
|
526
|
-
- Dynamic plugin system:
|
|
527
|
-
- User plugins: Drop custom language experts in `~/.garuda/languages/<lang>.js`.
|
|
528
|
-
- Project plugins (`<root>/.garuda/languages/`) are not loaded (merge gate). A plugin runs inside
|
|
529
|
-
Garuda's own process with no sandbox, there is no consent flow yet, and a hash pin of the entry file
|
|
530
|
-
does not cover the files it imports (G09). `/languages` names the plugins that were skipped.
|
|
531
|
-
- Tests and evals load the built-in experts only.
|
|
532
|
-
- Tools for the agent (read-only, no approval), chosen with `"codeIndex"` in `.garuda/settings.json`:
|
|
533
|
-
`"off"` (default), `"lookup"` (`find_symbol`, `find_references`, `find_callers`, `impact_analysis`, `ast_query`) or `"all"` (also `repo_map`).
|
|
534
|
-
`find_callers` traces structural invocation hierarchies across languages; `impact_analysis` computes blast radius, dependents, and discovers affected test suites (including Go `*_test.go` and Rust `*_test.rs`); `ast_query` filters symbols by kind, container, and wildcards.
|
|
535
|
-
- Chat commands for you: `/where X` (or `/defs X`), `/refs X`, `/callers X`, `/impact X`, `/map [folder]`, and `/languages` (lists active language plugins, indexed file counts, and standby status).
|
|
536
|
-
- The code graph (files, exports, imports) is cached in `.garuda/index/code-graph.json` by file hash.
|
|
537
|
-
Pure AST parsers run in-process and preserve single-binary distribution.
|
|
538
|
-
- Files follow `.gitignore`. Sensitive files are never indexed.
|
|
65
|
+
## User guide
|
|
539
66
|
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
Garuda features an autonomous Mixture-of-Experts (MoE) dispatch architecture for polyglot codebases:
|
|
543
|
-
|
|
544
|
-
- **Specialist profiles**: Dedicated subagents for Go, Rust, Python, Java, and TypeScript equipped with language-idiomatic prompts, toolchain testing commands (`cargo test`, `go test ./...`, `pytest`, `mvn test`, `pnpm test`), and scoped AST tools.
|
|
545
|
-
- **Dynamic delegation**: The primary orchestrator agent can invoke `delegate_expert({ language, task, files })` to dispatch complex language-specific tasks to child subagents. The child subagent runs with full AST code tools, executes language tests, and returns a synthesized report without cluttering the primary context window.
|
|
546
|
-
- **Chat command**: `/experts` lists all available language specialists, their active test commands, and their active status / indexed file counts.
|
|
547
|
-
- **Banner & Observability**: The startup banner features a dedicated `subagents` row (`subagents: explore · 5 MoE experts (Go, Rust, Python, Java, TS)`). In session, `/session` provides a full breakdown of active subagents, agents, skills, and tools.
|
|
548
|
-
- **Configuration**: off by default (no measured gain yet). Turn it on with `"moe": { "enabled": true }` in
|
|
549
|
-
`.garuda/settings.json`; `subagents` alone does not turn it on. One `delegate_expert` call runs at a
|
|
550
|
-
time, because a specialist can write files (merge gate, G05).
|
|
551
|
-
|
|
552
|
-
## Team policy and structured audit log (0.17, W5)
|
|
553
|
-
|
|
554
|
-
A team policy sets limits that a project cannot loosen, and an audit log records the permission decisions:
|
|
555
|
-
|
|
556
|
-
- **Team policy**: guardrails that a project's settings cannot loosen. Garuda reads the managed file
|
|
557
|
-
(`/Library/Application Support/Garuda/policy.json` on macOS, `/etc/garuda/policy.json` on Linux;
|
|
558
|
-
an admin writes it) and `~/.garuda/policy.json`. Where both exist, the stricter value wins: lists of
|
|
559
|
-
denials add up, `requireSandbox` and `strictAllowlist` are on when either sets them, limits take the
|
|
560
|
-
lower value, and `allowedModels` and `audit` come from the managed file when it sets them. A broken
|
|
561
|
-
file stops Garuda. A project's own `.garuda/policy.json` is ignored with a notice: a cloned repo
|
|
562
|
-
could otherwise remove its own limits. The chat, `-p`, jobs, the night shift and `garuda eval` all
|
|
563
|
-
use the policy. `/audit` names the files. The keys:
|
|
564
|
-
- `disallowedCommands`: command patterns that are denied in every run (for example
|
|
565
|
-
`["rm -rf *", "git push *--force*"]`). A compound command is denied when one of its parts matches.
|
|
566
|
-
- `requireSandbox`: When `true`, no command runs outside the OS sandbox: `outside_sandbox` is
|
|
567
|
-
denied, and on a machine with no OS sandbox every command is denied.
|
|
568
|
-
- `denyPaths`: root-relative path patterns that the agent may not read or write (for example
|
|
569
|
-
`["**/.env*", "secret/**"]`). File tools refuse them; `grep`, `glob` and the code index skip them
|
|
570
|
-
(no content, no name). Commands in the OS sandbox cannot read or write them either: the matching
|
|
571
|
-
files and folders are added to the sandbox profile when each command starts (not searched:
|
|
572
|
-
`node_modules`, `.git`; at most 1,000 paths). A symbolic link to a denied file is denied too.
|
|
573
|
-
- `allowedModels`: Allowlist of LLM models permitted for use in the organization.
|
|
574
|
-
- `network`: `blockedHosts` (`*.example.com` for subdomains) and `strictAllowlist`. A blocked host
|
|
575
|
-
stays blocked for `web_fetch` and for sandboxed commands, also when the project's
|
|
576
|
-
`network.allow` lists it.
|
|
577
|
-
- `limits`: Global caps on `maxSteps` and `tokenBudget`. They hold for each subagent run too
|
|
578
|
-
(explore, custom agents, MoE specialists), whatever the `subagents` or `moe` settings say (0.14).
|
|
579
|
-
- **Structured audit log** (`~/.garuda/audit/<project>-<hash>/`, one file per Garuda process): on in
|
|
580
|
-
the chat, `-p` and jobs (a job writes under its main checkout's folder, so the log outlives the
|
|
581
|
-
worktree); off in evals and tests; the team policy can turn it off (`audit.enabled: false`) or make it
|
|
582
|
-
mandatory (`audit.enabled: true`: a failed write then fails the call with an error result, and
|
|
583
|
-
says whether the call ran). Without a policy a failed write
|
|
584
|
-
gives one notice. It is not in the project, so the agent's own tools cannot edit it. Targets and
|
|
585
|
-
reasons pass the session redactor, so known secret formats (keys, tokens, `password=…`) are removed. Each line has `seq`,
|
|
586
|
-
`prev` and `hash` (sha256): `/audit verify` shows a changed, removed or inserted line, but not lines
|
|
587
|
-
cut from the end of a file or a removed file. This makes the log tamper-evident, not tamper-proof:
|
|
588
|
-
a user who can write the file can rewrite the whole chain.
|
|
589
|
-
Each line records:
|
|
590
|
-
- Every authorization decision (`allow_readonly`, `allow_sandbox`, `deny_policy`, `deny_user`, etc.).
|
|
591
|
-
- Security risk classification (`low`, `medium`, `high`, `critical`).
|
|
592
|
-
- Tool execution duration in milliseconds and error status, also for the tool calls of a subagent
|
|
593
|
-
(0.14).
|
|
594
|
-
- Calls that a preToolUse hook blocked, and each hook command that ran (0.14). The team policy's
|
|
595
|
-
`requireSandbox` and `disallowedCommands` hold for hook commands too.
|
|
596
|
-
- **Chat command**: `/audit` displays active policy rules and recent audit events. Use `/audit stats` for totals, `/audit denials` for security blocks, `/audit verify` to check the hash chains, or `/audit <n>` for recent events.
|
|
597
|
-
|
|
598
|
-
## Sessions, limits and context
|
|
599
|
-
|
|
600
|
-
Every run writes a session file: `.garuda/sessions/<id>.jsonl` (one JSON record per line, mode 0600).
|
|
601
|
-
It holds every message, tool call, result, token count and cost. Garuda redacts known secret
|
|
602
|
-
formats (API keys, tokens, private keys, `password=…`) and the values of secret-looking environment
|
|
603
|
-
variables before it writes a line. The model can still see a secret; the file never holds it.
|
|
604
|
-
|
|
605
|
-
```sh
|
|
606
|
-
garuda -p "Find the flaky test" # new session
|
|
607
|
-
garuda --resume -p "Now fix it" # continue the latest session
|
|
608
|
-
garuda --resume 20260923-201500-a1b2 -p "…" # continue a given session
|
|
609
|
-
garuda --replay 20260923-201500-a1b2 # replay it: no API calls, no tools run
|
|
610
|
-
```
|
|
611
|
-
|
|
612
|
-
- After each turn Garuda prints steps, tokens (with cache reads), cost, context use and the session total.
|
|
613
|
-
- A run stops at 50 steps, at the session token budget (20M tokens), or after the same tool call
|
|
614
|
-
3 times in a row. Garuda says why.
|
|
615
|
-
- When the connection to the model breaks while a response streams, Garuda sends the request again (up
|
|
616
|
-
to 2 times) and says so. The session keeps only the complete response.
|
|
617
|
-
- At 80% of the context window, Garuda first cuts long tool outputs in older turns. If that is not enough,
|
|
618
|
-
the model summarises the older turns. The last 4 turns always stay in full.
|
|
619
|
-
- `AGENTS.md`, `CLAUDE.md` and `GARUDA.md` in the project root go into the system prompt, in that order;
|
|
620
|
-
`GARUDA.md` wins on a conflict. A file with the same text as an earlier one goes in once.
|
|
621
|
-
- Project memory: the `remember` tool saves lasting facts (build and test commands, layout, conventions)
|
|
622
|
-
to `.garuda/memory.md`, with your approval. The next session loads them after `GARUDA.md`.
|
|
623
|
-
Edit or delete lines freely. Add `remember` to `permissions.allow` to skip the question.
|
|
624
|
-
- `read_file` does not send the same lines of an unchanged file twice. After compaction it sends them again.
|
|
625
|
-
- Garuda knows the price and context window of current Claude models. For other models, set them in settings.
|
|
626
|
-
|
|
627
|
-
## Sandbox
|
|
628
|
-
|
|
629
|
-
Garuda runs commands in an OS sandbox: Seatbelt (`sandbox-exec`) on macOS, bubblewrap (`bwrap`) on Linux.
|
|
630
|
-
In the sandbox, a command:
|
|
631
|
-
|
|
632
|
-
- can read every file, except secrets in your home folder (`~/.ssh`, `~/.aws`, `~/.gnupg`, `~/.kube`,
|
|
633
|
-
`~/.docker`, `~/.netrc`, `~/.npmrc`, `~/.git-credentials`, keychains, Garuda's and Claude Code's tokens and more);
|
|
634
|
-
- can write only in the working root, the temp folders and package caches (`~/.cache`, `~/.npm`, pnpm,
|
|
635
|
-
and for a Java or Python project `~/.m2/repository`, `~/.gradle/caches` and similar);
|
|
636
|
-
- cannot write `.git/hooks`, `.git/config` or `.garuda/` in the root, because those run or apply later
|
|
637
|
-
outside the sandbox;
|
|
638
|
-
- has no network (localhost works on macOS), unless you open a network allowlist (0.13, below);
|
|
639
|
-
- cannot start apps on macOS (`open`, `osascript`), because an app started that way runs outside the
|
|
640
|
-
sandbox (0.14);
|
|
641
|
-
- sees only its own processes on Linux, not Garuda's or yours (0.14).
|
|
642
|
-
|
|
643
|
-
Commands in the sandbox run with no approval. Deny rules still apply. When the sandbox blocks a command
|
|
644
|
-
(for example `pnpm install` needs the network), the model can ask to run it outside the sandbox.
|
|
645
|
-
That always asks you first, and the prompt says "OUTSIDE the sandbox".
|
|
646
|
-
|
|
647
|
-
Settings:
|
|
648
|
-
|
|
649
|
-
```json
|
|
650
|
-
{
|
|
651
|
-
"executor": "auto",
|
|
652
|
-
"sandbox": { "writePaths": ["~/tools/cache"], "denyRead": ["~/work-secrets"] }
|
|
653
|
-
}
|
|
654
|
-
```
|
|
655
|
-
|
|
656
|
-
- `executor`: `auto` (default) uses the sandbox when it works on this machine, else runs on the host
|
|
657
|
-
with a notice. `os` requires the sandbox. `host` turns it off, and every command asks again.
|
|
658
|
-
- `sandbox.writePaths` and `sandbox.denyRead` add paths. `~/` is the home folder; other relative paths
|
|
659
|
-
start at the root.
|
|
660
|
-
- macOS sandbox probe (0.14): at startup Garuda runs `true` through `/usr/bin/sandbox-exec` once. When
|
|
661
|
-
that fails (for example in a nested sandbox), `auto` falls back to the host with a notice that gives
|
|
662
|
-
the first line of the error.
|
|
663
|
-
- On Linux, install bubblewrap (`sudo apt install bubblewrap`). Some systems block the user namespaces
|
|
664
|
-
that it needs; Garuda then falls back to the host and says why.
|
|
665
|
-
|
|
666
|
-
### Network allowlist (0.13)
|
|
667
|
-
|
|
668
|
-
Installs and builds need a package registry, but not the whole internet. The allowlist lets commands in
|
|
669
|
-
the sandbox reach named hosts through Garuda's own proxy, with no question:
|
|
670
|
-
|
|
671
|
-
```json
|
|
672
|
-
{ "network": { "allow": ["npm", "pypi", "api.example.com", "*.example.org"] } }
|
|
673
|
-
```
|
|
674
|
-
|
|
675
|
-
- Presets: `npm`, `pypi`, `maven`, `go`, `cargo`, `github` (each names its registry hosts). A host with
|
|
676
|
-
`*.` matches its subdomains. Only ports 80 and 443.
|
|
677
|
-
- Off by default. The first turn shows the list and asks; "remember" pins it to the list in
|
|
678
|
-
`~/.garuda/trust.json`, so a changed list asks again. The model then gets a note that names the hosts,
|
|
679
|
-
so it runs those commands in the sandbox and does not ask to leave it.
|
|
680
|
-
- A host that is not on the list asks you (once, this session, or no); `network(host)` in
|
|
681
|
-
`permissions.allow` or `permissions.deny` answers for good. Jobs and evals deny it and say which host.
|
|
682
|
-
- Commands get `HTTP_PROXY` and `HTTPS_PROXY`: npm, pnpm, yarn, pip, cargo, go, git and curl use them;
|
|
683
|
-
Node's `fetch` too (`NODE_USE_ENV_PROXY`, Node 24 or later); Maven and Gradle through `MAVEN_OPTS` and
|
|
684
|
-
`GRADLE_OPTS`. A tool that ignores the proxy variables still has no network.
|
|
685
|
-
- The proxy does not read the traffic: for https it sees only the host name. A host must resolve to
|
|
686
|
-
public addresses; the proxy connects to the address it checked.
|
|
687
|
-
- On Linux the proxy reaches bubblewrap's network namespace through a small bridge that runs with
|
|
688
|
-
`node`; with no `node` on the PATH the allowlist stays off and Garuda says so.
|
|
689
|
-
- A job keeps the list that was in effect when you scheduled it (the approval shows it).
|
|
690
|
-
`garuda eval --network npm,pypi` measures a suite with the list.
|
|
691
|
-
- Limit on Linux: a protected path that does not exist yet (for example `.git/hooks` in a folder with no
|
|
692
|
-
`.git`) is not protected.
|
|
693
|
-
|
|
694
|
-
### Background daemons (0.14, off by default)
|
|
695
|
-
|
|
696
|
-
Dev servers and watchers can run in the background. This is off by default (no measured gain yet).
|
|
697
|
-
Turn it on with `"daemons": { "enabled": true }` in `.garuda/settings.json`.
|
|
698
|
-
|
|
699
|
-
- With the setting on, `bash` takes `is_daemon: true`: the command starts through the same executor
|
|
700
|
-
(the same sandbox and approval as any command) and the tool returns at once with a `daemonId`.
|
|
701
|
-
- The `process_manager` tool has `list`, `status`, `logs` (`lines`, `stream`) and `kill` for daemons
|
|
702
|
-
that Garuda started in this session. `list`, `status` and `logs` run without a question; `kill`
|
|
703
|
-
asks (or follows a rule) and is refused in plan mode.
|
|
704
|
-
- Logs are kept in memory: the newest 2,000 lines per daemon, at most 4,000 characters per line, and
|
|
705
|
-
`logs` returns at most 30,000 characters (the newest lines).
|
|
706
|
-
- When the session closes, Garuda stops every running daemon (SIGTERM to the process group, then
|
|
707
|
-
SIGKILL).
|
|
708
|
-
|
|
709
|
-
## Custom agents
|
|
710
|
-
|
|
711
|
-
A custom agent is a Markdown file in Claude Code's subagent format. Garuda reads your Claude Code agents
|
|
712
|
-
where they are.
|
|
713
|
-
|
|
714
|
-
```markdown
|
|
715
|
-
<!-- ~/.garuda/agents/test-writer.md (or ~/.claude/agents, .garuda/agents, .claude/agents) -->
|
|
716
|
-
---
|
|
717
|
-
name: test-writer
|
|
718
|
-
description: Writes unit tests for a module. Use when the user asks for tests.
|
|
719
|
-
tools: Read, Grep, Glob, Write, Bash
|
|
720
|
-
model: haiku
|
|
721
|
-
---
|
|
722
|
-
You write focused unit tests with the project's test tool. Run them before you answer.
|
|
723
|
-
```
|
|
724
|
-
|
|
725
|
-
- The model hands a task to an agent with the `agent` tool. The agent works in its own context with its
|
|
726
|
-
own instructions and tools, and returns a short report. Agents cannot start agents.
|
|
727
|
-
- Without `tools`, an agent can only read. Named write tools and bash still ask or run in the sandbox,
|
|
728
|
-
and plan mode holds. An agent that may write never runs at the same time as another call.
|
|
729
|
-
- `model`: `haiku`, `sonnet`, `opus`, or a model id (your own agents only). Default: `--subagent-model`,
|
|
730
|
-
else the main model. Its tokens and cost count in the session.
|
|
731
|
-
- A project agent shows its tools and instructions and asks the first time. Your own agents win over
|
|
732
|
-
project agents with the same name (in Claude Code, the project wins).
|
|
733
|
-
- `/agents` lists them. Nothing changes without agent files; `"agents": { "enabled": false }` turns them
|
|
734
|
-
off. Details: [docs/lld/agents.md](docs/lld/agents.md).
|
|
735
|
-
|
|
736
|
-
## Explore subagent
|
|
737
|
-
|
|
738
|
-
Off by default. Turn it on with `"subagents": { "enabled": true }` in `.garuda/settings.json`.
|
|
739
|
-
An A/B eval on the hard suite showed no gain in steps or cost (details in `docs/lld/agents.md`); it may
|
|
740
|
-
help in long chats on large repositories.
|
|
741
|
-
|
|
742
|
-
For an open question about the code ("where is the coupon applied, and who calls it?"), the model can
|
|
743
|
-
call `explore`. A subagent searches with `glob`, `grep` and `read_file` in its own context and returns a
|
|
744
|
-
short answer with `path:line` references. The main context stays small, and several explore calls can
|
|
745
|
-
run at once.
|
|
746
|
-
|
|
747
|
-
- The subagent can only read. It uses the same permissions and hooks, so secrets stay blocked.
|
|
748
|
-
- Limits per call: 20 steps and 150 000 tokens. When it hits a limit, it still answers with what it
|
|
749
|
-
found, and says so.
|
|
750
|
-
- It uses the main model. `--subagent-model <spec>` (or `GARUDA_SUBAGENT_MODEL`) picks another one, for
|
|
751
|
-
example `claude-haiku-4-5` under Sonnet. Its tokens and cost count in the session totals.
|
|
752
|
-
- The chat shows one live line per call (`explore … · step 3 · grep /coupon/`); Ctrl-O shows the answer
|
|
753
|
-
and what it searched. Each run has its own file in `.garuda/sessions/<session id>/`.
|
|
754
|
-
- Settings: `"subagents": { "enabled": true, "maxSteps": 20, "tokenBudget": 150000 }`.
|
|
755
|
-
|
|
756
|
-
## Java and Python projects
|
|
757
|
-
|
|
758
|
-
Garuda finds the build tool from files in the working root and tells the model how to build and test.
|
|
759
|
-
The banner shows what it found, for example `Java (Maven)`.
|
|
760
|
-
|
|
761
|
-
| Found | Test command | The sandbox may also write |
|
|
762
|
-
| --- | --- | --- |
|
|
763
|
-
| `pom.xml` | `mvn -B -q -o test` (or `./mvnw`) | `~/.m2/repository`, `~/.m2/wrapper` |
|
|
764
|
-
| `build.gradle(.kts)`, `settings.gradle(.kts)` | `gradle test --offline -q` (or `./gradlew`) | `~/.gradle/caches`, `wrapper`, `daemon` and other cache folders |
|
|
765
|
-
| `pyproject.toml`, `setup.py`, `requirements.txt` … | `python3 -m pytest -q` (or the project's `.venv`, `uv run`, `poetry run`) | `~/.local/share/uv` |
|
|
766
|
-
|
|
767
|
-
- The commands run offline, because the sandbox has no network. When a dependency is missing, the model
|
|
768
|
-
asks to run the download outside the sandbox, and you approve it.
|
|
769
|
-
- Settings files and init scripts (`~/.m2/settings.xml`, `~/.gradle/init.d`, `gradle.properties`) stay
|
|
770
|
-
read-only: the build tool runs them later, outside the sandbox.
|
|
771
|
-
- `GARUDA.md` can override the detected commands. Gradle in the sandbox is not tested yet.
|
|
772
|
-
|
|
773
|
-
## MCP servers
|
|
774
|
-
|
|
775
|
-
Garuda connects to local MCP servers over stdio (0.2) and to remote servers over Streamable HTTP,
|
|
776
|
-
with OAuth sign-in (0.4).
|
|
777
|
-
|
|
778
|
-
```json
|
|
779
|
-
{
|
|
780
|
-
"servers": {
|
|
781
|
-
"github": {
|
|
782
|
-
"command": "github-mcp-server",
|
|
783
|
-
"args": ["stdio"],
|
|
784
|
-
"env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}" },
|
|
785
|
-
"network": true
|
|
786
|
-
}
|
|
787
|
-
}
|
|
788
|
-
}
|
|
789
|
-
```
|
|
790
|
-
|
|
791
|
-
- Your own servers go in `~/.garuda/mcp.json`. A project can add servers in `.garuda/mcp.json`.
|
|
792
|
-
- Keys per server: `command`, `args`, `env`, `network` (default false), `writePaths`,
|
|
793
|
-
`timeoutMs` (default 60000), `enabled`. `${NAME}` in an env value comes from your environment,
|
|
794
|
-
so secrets stay out of the file.
|
|
795
|
-
- Servers start with the first task. `/mcp` shows their state.
|
|
796
|
-
- A remote server needs only its URL: `"linear": { "url": "https://mcp.linear.app/mcp" }`. When it
|
|
797
|
-
asks for a sign-in, Garuda asks you, opens your browser, and keeps the tokens in
|
|
798
|
-
`~/.garuda/mcp-auth.json` (only you can read it). Tokens refresh by themselves;
|
|
799
|
-
`/mcp logout <server>` removes them.
|
|
800
|
-
|
|
801
|
-
Security:
|
|
802
|
-
|
|
803
|
-
- A project server can come from a cloned repo, so Garuda asks before it starts one. The question
|
|
804
|
-
shows the full command, the sandbox, the network setting, the env variables and warnings
|
|
805
|
-
(npx, shell commands, secrets). "Remember" pins your answer to a hash of the definition in
|
|
806
|
-
`~/.garuda/trust.json`; any change asks again. A project cannot replace one of your own servers.
|
|
807
|
-
- A remote server is not in the sandbox: it runs on another computer and gets the arguments of its
|
|
808
|
-
tool calls. A project's remote server needs your consent (pinned to its URL), must use https and a
|
|
809
|
-
public address, and Garuda checks the address at each connection.
|
|
810
|
-
- Each local server runs in the OS sandbox, like bash: it can write only in the project and temp folders,
|
|
811
|
-
cannot read `~/.ssh` and other secrets, and has no network unless `"network": true`.
|
|
812
|
-
It gets only the normal environment variables and the ones in its `env`.
|
|
813
|
-
- Garuda remembers each server's tools (a hash per tool). When they change later (a "rug pull"),
|
|
814
|
-
Garuda warns you and says which tools were added, removed or changed, with the new descriptions.
|
|
815
|
-
A project server needs your consent again.
|
|
816
|
-
- When a configured server is not available (you said no, it failed or it stopped), Garuda tells
|
|
817
|
-
the model once in a `<garuda_note>`, so the model says so instead of guessing. Server text cannot
|
|
818
|
-
pose as such a note or close its `<mcp_result>` wrapper.
|
|
819
|
-
- Every MCP tool call asks for approval and shows its arguments. Server hints such as
|
|
820
|
-
`readOnlyHint` are shown, never trusted. Allow rules skip the question:
|
|
821
|
-
`mcp__github__get_issue` or `mcp__github__*`.
|
|
822
|
-
- Tool names get the prefix `mcp__<server>__`, so a server cannot replace a Garuda tool.
|
|
823
|
-
- Descriptions and results are cleaned (terminal escape codes, control, invisible and Unicode tag
|
|
824
|
-
characters), limited in size, and marked as untrusted for the model (`<mcp_result>`).
|
|
825
|
-
- Garuda offers no sampling, roots or elicitation, so a server cannot make model calls or ask
|
|
826
|
-
you questions through Garuda.
|
|
827
|
-
- The evals never start MCP servers.
|
|
828
|
-
|
|
829
|
-
## Web fetch
|
|
830
|
-
|
|
831
|
-
`web_fetch` reads a web page (http or https) and gives it to the model as Markdown (0.2).
|
|
832
|
-
|
|
833
|
-
- The first fetch from a host asks you and shows the full URL. "Yes, allow <host> for this session"
|
|
834
|
-
skips later questions for that host. Rules skip the question for good:
|
|
835
|
-
`web_fetch(docs.python.org)`, or `web_fetch(*.github.com)` for its subdomains.
|
|
836
|
-
- An unusual URL (very long, or with a long token that could carry data from the session) always asks,
|
|
837
|
-
also for an allowed host.
|
|
838
|
-
- A redirect to another host asks like a new fetch.
|
|
839
|
-
- Protection against server-side request forgery: Garuda resolves each host itself, checks every
|
|
840
|
-
address (only public addresses; no private, loopback, link-local such as 169.254.169.254, or other
|
|
841
|
-
special ranges, also as IPv4-mapped IPv6), and connects to exactly the checked address. Redirects
|
|
842
|
-
are followed by hand (at most 5) and checked the same way.
|
|
843
|
-
- http is upgraded to https. URLs with a user name or password are refused. Garuda sends no cookies
|
|
844
|
-
and no credentials, and it does not use a proxy.
|
|
845
|
-
- Limits: 5 MB per page (also after decompression), 30 s, text types only. HTML becomes Markdown
|
|
846
|
-
without scripts, styles and navigation. Long pages come in parts (`start`, `max_chars`); a page is
|
|
847
|
-
cached for 10 minutes.
|
|
848
|
-
- Page text is cleaned like MCP text and marked as untrusted (`<web_result>`).
|
|
849
|
-
- Settings: `"web": { "enabled": false }` removes the tool. `"web": { "allowLocalhost": true }` allows
|
|
850
|
-
loopback addresses (for a local docs server); private network ranges stay blocked.
|
|
851
|
-
- The evals turn web_fetch off.
|
|
852
|
-
|
|
853
|
-
## Web search
|
|
854
|
-
|
|
855
|
-
`web_search` finds pages for a query (0.5). Set a key and it appears:
|
|
856
|
-
|
|
857
|
-
```sh
|
|
858
|
-
export BRAVE_API_KEY=... # Brave Search, or:
|
|
859
|
-
export TAVILY_API_KEY=... # Tavily
|
|
860
|
-
```
|
|
861
|
-
|
|
862
|
-
Or pick a backend in `~/.garuda/search.json`: `{ "provider": "brave" }`, `{ "provider": "tavily" }`, or
|
|
863
|
-
your own SearXNG server: `{ "provider": "searxng", "url": "http://localhost:8888" }` (turn on its JSON
|
|
864
|
-
format). Keys come only from environment variables; a project cannot configure search.
|
|
865
|
-
|
|
866
|
-
- The query leaves your machine, so each search shows the query and asks. "Yes, for this session" skips
|
|
867
|
-
the question for later searches; `"permissions": { "allow": ["web_search"] }` skips it for good (and allows
|
|
868
|
-
searches in plan mode).
|
|
869
|
-
- A query with a long token (it could be a key) is refused.
|
|
870
|
-
- Results are titles, URLs and short texts, marked as untrusted. The model reads pages with `web_fetch`.
|
|
871
|
-
- `"web": { "enabled": false }` removes both web tools. Details: [docs/lld/web.md](docs/lld/web.md).
|
|
872
|
-
|
|
873
|
-
### Claude's web search (0.6)
|
|
874
|
-
|
|
875
|
-
With a Claude model, the model can use Claude's own search tool, which runs on Anthropic's servers. Turn it
|
|
876
|
-
on with a `claude` section in `~/.garuda/search.json`:
|
|
877
|
-
|
|
878
|
-
```json
|
|
879
|
-
{ "claude": { "maxUses": 5 } }
|
|
880
|
-
{ "provider": "tavily", "claude": { "blockedDomains": ["example.com"] } }
|
|
881
|
-
```
|
|
882
|
-
|
|
883
|
-
- The search runs inside the model's reply, so Garuda cannot ask before each query. Choose once which
|
|
884
|
-
web search you want, with `"use"` in `~/.garuda/search.json`: `"claude"` (Claude's search; your other
|
|
885
|
-
backend stays the fallback for other models), `"provider"` (only your other backend) or `"off"`.
|
|
886
|
-
`garuda init` asks it when Claude's search is set up and nothing is saved; without a saved choice,
|
|
887
|
-
the chat asks once before the first task and saves the answer. No session asks again.
|
|
888
|
-
- `/search` shows what is in use. `/search claude|provider|off` switches for this session;
|
|
889
|
-
`/search default claude|provider|off` changes the saved choice.
|
|
890
|
-
- It costs $10 per 1,000 searches, on top of the tokens. The usage line and `/usage` include it.
|
|
891
|
-
- `maxUses` (1–20, default 5) caps the searches per model request. `allowedDomains` or `blockedDomains`
|
|
892
|
-
(not both) limit the sites.
|
|
893
|
-
- Your other backend (`provider`, or a key in the environment) is the fallback: for a model that is not a
|
|
894
|
-
Claude model (for example after `/models`), or with `"use": "provider"`. Without one, `provider` is
|
|
895
|
-
not offered.
|
|
896
|
-
- Custom agents whose tools allow `WebSearch` (or `web_search`) get it too, in the same session.
|
|
897
|
-
- The chat shows each search: `● web_search (Claude) <query>` and the number of results; Ctrl-O lists
|
|
898
|
-
the pages.
|
|
899
|
-
|
|
900
|
-
## Scheduled jobs (0.7)
|
|
901
|
-
|
|
902
|
-
A plan can run later, with nobody at the keyboard: for example overnight.
|
|
903
|
-
|
|
904
|
-
1. Make a plan in plan mode (`/plan`, then your task). Each plan now ends with a `permissions` block: the
|
|
905
|
-
file edits and network commands the build needs.
|
|
906
|
-
2. At "Build this plan?", choose "No, keep planning", and type `/schedule 01:00` (the time is optional).
|
|
907
|
-
Garuda shows the approval list, where the job starts (your last commit, plus your uncommitted changes
|
|
908
|
-
of tracked files) and its branch, and asks once.
|
|
909
|
-
3. In a terminal in the project folder: `garuda run <job-id> --at 01:00`. It waits, then builds the plan in
|
|
910
|
-
its own worktree on the branch `garuda/job-<id>`. Your checkout does not change.
|
|
911
|
-
|
|
912
|
-
- The job asks nothing. Reads, commands in the sandbox and the calls in its list are allowed; any other call
|
|
913
|
-
is denied, and the job goes on and reports it. You can edit the list (`"allow"`) in
|
|
914
|
-
`.garuda/jobs/<id>.json` before the run.
|
|
915
|
-
- A job needs git and the OS sandbox. `node_modules` and `.venv` are linked from your checkout.
|
|
916
|
-
- At the end Garuda commits the changes on the job branch (no git hooks run) and writes a report:
|
|
917
|
-
`.garuda/jobs/<id>.md`, also shown by `/jobs <id>`. Review with `git diff`, then `git merge
|
|
918
|
-
garuda/job-<id>`, and remove the worktree.
|
|
919
|
-
- `/jobs` lists the jobs. Keep the Mac awake and on power while the terminal waits.
|
|
920
|
-
- `/jobs delete <id>` (0.11) asks, then removes the job file, report, log and worktree. An unmerged job
|
|
921
|
-
branch may hold work: you choose to keep it or delete it too. A running job cannot be deleted.
|
|
922
|
-
- On macOS, `/schedule HH:MM` offers a launchd agent: the job then starts at that time also with no
|
|
923
|
-
terminal open. It runs through your login shell (so your `.zshrc` gives it the API keys) under
|
|
924
|
-
`caffeinate`, logs to `.garuda/jobs/<id>.log`, and sends a macOS notification at the end. If the Mac
|
|
925
|
-
sleeps at that time, the job starts at the next wake (`sudo pmset schedule wake "<date>"` can wake it).
|
|
926
|
-
`/jobs cancel <id>` removes the agent.
|
|
927
|
-
- With a Claude model, `/schedule` also asks whether the job should use the Batch API: half the token
|
|
928
|
-
price, but each step waits for its batch: about 3 minutes in the first measurement, sometimes hours.
|
|
929
|
-
A step that waits more than 20 minutes (`"stepLimitMinutes"`) runs on the normal API, and the next step
|
|
930
|
-
tries the Batch API again. 15 minutes before the finish-by time (`"finishBy": "07:00"` in the job file)
|
|
931
|
-
a job that still runs goes on with the normal API. The run prints the batch id and a line per minute
|
|
932
|
-
of waiting.
|
|
933
|
-
|
|
934
|
-
### The night shift (0.11)
|
|
935
|
-
|
|
936
|
-
Each `/schedule` also puts the job in the project's night queue. `garuda night --at 01:00` waits, then
|
|
937
|
-
runs the queued jobs, up to 3 at a time (`--parallel n`, 1 to 10), each in its own worktree and with its
|
|
938
|
-
own log (`.garuda/jobs/<id>.log`). At the end it writes one digest, `.garuda/jobs/night-<date>.md`: a row
|
|
939
|
-
per job with its verdict, tests, files, cost and branch, and why the others need a look. `/jobs` shows
|
|
940
|
-
which jobs are in the queue. A job with its own launchd agent is not in the queue.
|
|
941
|
-
|
|
942
|
-
On macOS, `/schedule HH:MM` asks whether launchd should start **the whole night queue** at that time
|
|
943
|
-
(one agent per project, `garuda night` through your login shell under `caffeinate`, log
|
|
944
|
-
`.garuda/jobs/night.log`, a macOS notification at the end), **only this job**, or nothing. A later
|
|
945
|
-
`/schedule HH:MM` moves the queue's agent to the new time. The agent removes itself after the run;
|
|
946
|
-
`/jobs` shows it, and `/jobs cancel night` removes it.
|
|
947
|
-
|
|
948
|
-
### Proof of work (0.11)
|
|
949
|
-
|
|
950
|
-
Each job report starts with a verdict: **Ready to merge** or **Needs a look**. It rests on three things:
|
|
951
|
-
|
|
952
|
-
- **Tests before and after.** Garuda finds the test command (a `test` script in `package.json`, run with
|
|
953
|
-
pnpm, yarn or npm by the lock file; else the Maven, Gradle or pytest command; else `node --test` when
|
|
954
|
-
there are `*.test.js` files) and runs it in the sandbox
|
|
955
|
-
at the job's base and again after the job. `"test"` in the job file changes or sets it.
|
|
956
|
-
- **Risk flags.** STOP: the job did not finish, or the tests fail after it. Look: no test command, test
|
|
957
|
-
files deleted or changed, dependency or build files changed, CI or environment files changed, a large
|
|
958
|
-
change, denied calls, tests that failed before and pass after.
|
|
959
|
-
- **A review.** The job's model works as a staff engineer. A second request to the same model, as a
|
|
960
|
-
principal engineer who knows the project's stack, reads the request, the plan, the diff, the test
|
|
961
|
-
results and the flags, and answers `VERDICT: ready | needs a look` with findings. It costs one model
|
|
962
|
-
call (shown in the report); `"review": false` in the job file turns it off.
|
|
963
|
-
|
|
964
|
-
A STOP flag always means "Needs a look"; otherwise the review decides.
|
|
965
|
-
|
|
966
|
-
## Hooks
|
|
967
|
-
|
|
968
|
-
Hooks are your own commands that run around the agent's tool calls (0.2).
|
|
969
|
-
|
|
970
|
-
```json
|
|
971
|
-
{
|
|
972
|
-
"hooks": {
|
|
973
|
-
"preToolUse": [
|
|
974
|
-
{ "tools": ["bash(git push*)"], "command": "echo 'Pushes need a review first.' >&2; exit 2" }
|
|
975
|
-
],
|
|
976
|
-
"postToolUse": [
|
|
977
|
-
{ "tools": ["edit_file", "write_file"], "command": "npx eslint \"$GARUDA_FILE\" >&2 || exit 2" }
|
|
978
|
-
]
|
|
979
|
-
}
|
|
980
|
-
}
|
|
981
|
-
```
|
|
982
|
-
|
|
983
|
-
- Your own hooks go in `~/.garuda/hooks.json`. A project can add hooks in `.garuda/hooks.json`; Garuda
|
|
984
|
-
shows every command and asks first, like for MCP servers. "Remember" pins the answer to a hash of
|
|
985
|
-
the hooks; any change asks again.
|
|
986
|
-
- `tools` uses the permission rule syntax (`edit_file`, `bash(git push*)`, `mcp__github__*`).
|
|
987
|
-
An empty list matches every tool. Keys: `command`, `tools`, `timeoutMs` (default 30000), `network`.
|
|
988
|
-
- `preToolUse` runs before the approval question. Exit 0 lets the call go on. Exit 2 blocks it, and
|
|
989
|
-
stderr tells the model why. Any other failure (another exit code, a timeout) also blocks the call:
|
|
990
|
-
a broken guard never lets a call through. A hook can block a call, never approve one.
|
|
991
|
-
- `postToolUse` runs after the call. Exit 2 adds stderr to the result as feedback for the model
|
|
992
|
-
(for example lint errors). Other failures only show a warning.
|
|
993
|
-
- Hooks run in the OS sandbox, with no network unless `"network": true`. They get
|
|
994
|
-
`$GARUDA_HOOK_EVENT`, `$GARUDA_TOOL`, `$GARUDA_FILE` (for file tools), `$GARUDA_COMMAND` (bash),
|
|
995
|
-
`$GARUDA_URL` (web_fetch), and `$GARUDA_HOOK_INPUT`: a JSON file with the tool input (and the result
|
|
996
|
-
for postToolUse).
|
|
997
|
-
- `/hooks` shows the active hooks. The evals run with no hooks.
|
|
998
|
-
|
|
999
|
-
## Permissions
|
|
1000
|
-
|
|
1001
|
-
Put rules in `.garuda/settings.json` in the project. Deny rules always win.
|
|
1002
|
-
|
|
1003
|
-
```json
|
|
1004
|
-
{
|
|
1005
|
-
"executor": "auto",
|
|
1006
|
-
"permissions": {
|
|
1007
|
-
"allow": ["bash(pnpm test*)", "bash(git status)", "edit_file(src/**)"],
|
|
1008
|
-
"deny": ["bash(rm -rf*)", "bash(git push*)"]
|
|
1009
|
-
},
|
|
1010
|
-
"env": { "allow": ["NODE_ENV"] },
|
|
1011
|
-
"limits": { "maxSteps": 50, "tokenBudget": 20000000 },
|
|
1012
|
-
"model": {
|
|
1013
|
-
"contextWindow": 200000,
|
|
1014
|
-
"price": { "input": 3, "output": 15, "cacheRead": 0.3, "cacheWrite": 3.75 }
|
|
1015
|
-
}
|
|
1016
|
-
}
|
|
1017
|
-
```
|
|
1018
|
-
|
|
1019
|
-
- A rule is `tool` (every call) or `tool(pattern)`.
|
|
1020
|
-
- File patterns are globs relative to the root. A name without `/` matches at any depth.
|
|
1021
|
-
- Command patterns use `*` for any text. Garuda splits a command at `;`, `&&`, `||`, `|` and `$(…)`.
|
|
1022
|
-
A deny rule blocks the command when one part matches, also behind `sudo`, `env` or `VAR=value`.
|
|
1023
|
-
An allow rule must match every part as written: `bash(pnpm test*)` does not cover
|
|
1024
|
-
`NODE_OPTIONS=… pnpm test` or `sudo pnpm test`.
|
|
1025
|
-
- Sensitive files (`.env*`, keys, `.npmrc`, `.aws/`, …) are blocked, also for reads, also through a
|
|
1026
|
-
symbolic link with another name. On macOS and Windows, path patterns ignore letter case
|
|
1027
|
-
(`.ENV` is `.env` there).
|
|
1028
|
-
An allow rule that names the file, for example `read_file(.env.example)`, unblocks it.
|
|
1029
|
-
- Write tools never change files in `.git/`.
|
|
1030
|
-
- Commands see only these environment variables: `PATH`, `HOME`, `USER`, `LOGNAME`, `SHELL`, `TERM`,
|
|
1031
|
-
`LANG`, `LC_ALL`, `LC_CTYPE`, `TMPDIR`, `TZ`, plus the names in `env.allow`. API keys stay out.
|
|
1032
|
-
- With no terminal on stdin (a pipe or CI), Garuda cannot ask, so it denies calls that need approval.
|
|
1033
|
-
- The project's file comes with the repository, so its parts that loosen safety need your yes first:
|
|
1034
|
-
`executor: "host"`, `permissions.allow`, `sandbox.writePaths`, `env.allow` and
|
|
1035
|
-
`web.allowLocalhost`. At startup the chat (and `-p` in a terminal) shows them and asks: yes for this
|
|
1036
|
-
run, yes and remember (pinned in `~/.garuda/trust.json`; a change asks again), or no. Without a yes,
|
|
1037
|
-
Garuda leaves those parts out and says so; the rest of the file (deny rules, limits, features)
|
|
1038
|
-
applies. A scheduled job uses them only when they are pinned. Settings that `garuda init` writes
|
|
1039
|
-
ask once at the next start too.
|
|
1040
|
-
|
|
1041
|
-
## Standalone binary
|
|
1042
|
-
|
|
1043
|
-
`pnpm package` builds one executable file, `bin/garuda`, for the machine you build on.
|
|
1044
|
-
It holds Node and all of Garuda, so the target machine does not need Node.
|
|
1045
|
-
It needs Node 25.5 or later to build (it uses `node --build-sea`).
|
|
1046
|
-
|
|
1047
|
-
```sh
|
|
1048
|
-
pnpm package
|
|
1049
|
-
./bin/garuda # greeting
|
|
1050
|
-
./bin/garuda --version
|
|
1051
|
-
sudo cp bin/garuda /usr/local/bin/ # optional: put it on your PATH
|
|
1052
|
-
```
|
|
1053
|
-
|
|
1054
|
-
Notes:
|
|
1055
|
-
|
|
1056
|
-
- The binary is about 100–150 MB, because it contains the Node runtime.
|
|
1057
|
-
- Build on each platform that you want to run on. A binary built on an Apple silicon Mac runs only on Apple silicon Macs.
|
|
1058
|
-
- On macOS, the script signs the binary ad hoc (`codesign --sign -`), so it runs on the machine that built it.
|
|
1059
|
-
- Homebrew's Node has single executables turned off. The script then downloads the official Node build of
|
|
1060
|
-
the same version from nodejs.org, checks its SHA-256 sum and keeps it in `~/.cache/garuda`.
|
|
1061
|
-
Set `GARUDA_SEA_NODE=/path/to/node` to use a Node binary of your choice, or `NODEJS_ORG_MIRROR` to use a mirror.
|
|
1062
|
-
|
|
1063
|
-
## Layout
|
|
1064
|
-
|
|
1065
|
-
| Folder | Holds |
|
|
67
|
+
| Page | What it covers |
|
|
1066
68
|
| --- | --- |
|
|
1067
|
-
|
|
|
1068
|
-
|
|
|
1069
|
-
|
|
|
1070
|
-
|
|
|
1071
|
-
|
|
|
1072
|
-
|
|
|
1073
|
-
|
|
|
1074
|
-
|
|
|
1075
|
-
|
|
|
1076
|
-
|
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
- Only `src/model/anthropic.ts` imports the Anthropic SDK (N1).
|
|
1088
|
-
- Only `src/sandbox/` may start processes (N8). Biome and a test enforce this.
|
|
1089
|
-
- Strict TypeScript. No `any` in public interfaces (N7).
|
|
1090
|
-
|
|
1091
|
-
## Contributions and CI
|
|
1092
|
-
|
|
1093
|
-
Every pull request runs `.github/workflows/ci.yml`: `pnpm check` and a build on Linux (with
|
|
1094
|
-
bubblewrap, so the sandbox tests run) and macOS (Seatbelt), and a gitleaks scan of the history. The
|
|
1095
|
-
jobs have read-only access and get no secrets. Changes to `main` need a pull request and a review by
|
|
1096
|
-
the code owner (`.github/CODEOWNERS`).
|
|
1097
|
-
|
|
1098
|
-
The website lives in `site/` (Astro and Starlight). Its docs pages are generated from `docs/` and this
|
|
1099
|
-
README at build time (`site/scripts/sync-docs.mjs`), so edit those files, not the generated pages.
|
|
1100
|
-
`.github/workflows/pages.yml` builds the site for each pull request that changes it, and deploys it
|
|
1101
|
-
to GitHub Pages from `main`. To work on it: `cd site && pnpm install --ignore-workspace && pnpm dev`.
|
|
1102
|
-
|
|
1103
|
-
A tag `v<version>` runs `.github/workflows/release.yml`, which publishes the npm package with npm
|
|
1104
|
-
trusted publishing (no token in the repository). The steps, the first publish and the Homebrew tap
|
|
1105
|
-
are in [docs/release.md](docs/release.md).
|
|
69
|
+
| [Install and first run](docs/guide/getting-started.md) | Install, `garuda setup`, the chat, one task, JSON output for scripts, the standalone binary. |
|
|
70
|
+
| [Models](docs/guide/models.md) | Claude, OpenAI-compatible providers, local models, prices and context windows. |
|
|
71
|
+
| [Chat, sessions and undo](docs/guide/chat.md) | The chat's keys and commands, sessions, limits, context, plan mode, undo, the todo list. |
|
|
72
|
+
| [Editors](docs/guide/editors.md) | Zed, JetBrains, Neovim, Emacs and VS Code over the Agent Client Protocol. |
|
|
73
|
+
| [Project instructions, commands, skills and agents](docs/guide/projects.md) | `garuda init`, custom slash commands, skills, custom agents, subagents, Java and Python projects. |
|
|
74
|
+
| [Sandbox, permissions and policy](docs/guide/safety.md) | The OS sandbox, the network allowlist, staged commands, permissions, hooks, the team policy, the audit log. |
|
|
75
|
+
| [MCP, web and code intelligence](docs/guide/tools.md) | MCP servers, web fetch and search, the code index, language plugins, LSP diagnostics, formatters. |
|
|
76
|
+
| [Scheduled jobs and the night shift](docs/guide/jobs.md) | Plan now, build later on its own branch, with tests before and after and a review. |
|
|
77
|
+
| [Evals](docs/guide/evals.md) | Measure a model or a setting on eval tasks, also tasks from your repo's history. |
|
|
78
|
+
| [Status and known limits](docs/guide/status.md) | What each release added, and the known limits of this version. |
|
|
79
|
+
|
|
80
|
+
Design documents: [docs/](docs/README.md) (architecture, high-level design, low-level design per
|
|
81
|
+
component). The requirements doc defines the scope; code, tests and commits refer to its IDs
|
|
82
|
+
(F1–F26, N1–N8).
|
|
83
|
+
|
|
84
|
+
## Contributing
|
|
85
|
+
|
|
86
|
+
Contributions are welcome. Read [CONTRIBUTING.md](CONTRIBUTING.md) first: how to build, test and
|
|
87
|
+
send a pull request. Everyone who takes part follows the [Code of Conduct](CODE_OF_CONDUCT.md). To
|
|
88
|
+
report a security problem, see [SECURITY.md](SECURITY.md); do not open a public issue for it.
|
|
1106
89
|
|
|
1107
90
|
## License
|
|
1108
91
|
|
|
1109
92
|
Garuda is licensed under the [Apache License, Version 2.0](LICENSE). See [NOTICE](NOTICE).
|
|
1110
|
-
To report a security problem, see [SECURITY.md](SECURITY.md).
|