@garuda-agent/garuda 0.0.1 → 0.14.1

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