Init (src/init/)
This page is generated from
docs/lld/init.mdin the repository.
Purpose
Section titled “Purpose”garuda init and /init set up a folder for Garuda (0.5):
- Migrate. Read the files of other coding agents, show what goes where, and write new files after one yes.
- git. Offer
git initwhen the folder is not a repository. - The init turn. Give the model a prompt. In a code project, it reads the code and writes or
improves
AGENTS.md. In an empty folder, it asks what to build first.
Steps 1 and 2 run no model. The init turn uses the normal tools, so each file write shows its diff and asks.
OpenCode has /init too (it writes AGENTS.md). It does not import MCP servers, commands or rules from
other agents. Garuda does both.
| File | Role |
|---|---|
types.ts |
ImportItem: mcp, command, rule, instructions, skipped. Each has agent, source and notes. |
convert.ts |
Pure conversions: names, env values, Markdown and TOML commands, Claude Code and OpenCode rules, JSONC. |
sources.ts |
One reader per agent. Reads only; runs nothing. loadToml() loads the TOML reader on demand (N3). |
plan.ts |
buildPlan (where each item goes), previewText, applyPlan. |
detect.ts |
folderKind (code, notes, empty) and initTip (the hint on the chat start banner). |
run.ts |
runInit: the three steps; initPrompt. |
What Garuda reads
Section titled “What Garuda reads”| Agent | MCP servers | Commands | Rules | Instructions |
|---|---|---|---|---|
| Claude Code | .mcp.json, ~/.claude.json (top level and this project) |
.claude/commands, ~/.claude/commands |
.claude/settings.json, .claude/settings.local.json |
CLAUDE.md is read natively |
| OpenCode | opencode.json(c), ~/.config/opencode/opencode.json(c) |
.opencode/command(s), the command key |
permission (project file) |
AGENTS.md is native |
| Codex | .codex/config.toml, ~/.codex/config.toml |
~/.codex/prompts |
– | AGENTS.md is native |
| Gemini CLI | .gemini/settings.json, ~/.gemini/settings.json |
.gemini/commands/**/*.toml |
– | GEMINI.md |
| Tabnine | .tabnine/agent/settings.json, .tabnine/mcp_servers.json, ~/.tabnine/agent/settings.json |
.tabnine/agent/commands/**/*.toml |
– | TABNINE.md, .tabnine/guidelines/ |
| Cursor | .cursor/mcp.json, ~/.cursor/mcp.json |
– | – | .cursorrules, .cursor/rules/*.mdc |
| Copilot | – | – | – | .github/copilot-instructions.md, .github/instructions/ |
A missing file gives nothing. A file that does not parse gives one skipped item, and the rest is still read.
At most 200 files per command folder.
A symbolic link in a project’s command folders is skipped (0.14.1, review: a link to ~/.ssh/id_rsa
was copied into .garuda/commands). The user’s own folders may hold links.
Conversions
Section titled “Conversions”| From | To | Rule |
|---|---|---|
| Server name | [a-z0-9_], up to 32 |
Lower case; other characters become _. No valid name: skipped. |
| stdio server | {command, args, env} |
cwd is left out (note). A note says it runs in the sandbox with no network. |
| Remote server | {url} |
Streamable HTTP only. Claude type: "sse" and Gemini url (without httpUrl) are SSE: skipped. The URL must pass checkServerUrl (project servers: https and a public address). Headers are not copied (note): Garuda signs in with OAuth. |
| Disabled server | enabled: false |
It stays off. |
| env value | ${VAR} stays; OpenCode {env:VAR} becomes ${VAR} |
A literal value under a secret-like name (KEY, TOKEN, SECRET, PASS, CRED, AUTH) is not copied: it becomes ${NAME}, with a note. Codex env_vars become ${VAR}. |
| Server args | copied | An argument that looks like a secret (--api-key, sk-…, ghp_…) gives a note to check the new file. |
| Markdown command | Garuda command file | description and argument-hint stay; other front-matter keys are left out (note). !`cmd` and @file stay as text (note). |
| TOML command | Garuda command file | prompt is the body, description stays, {{args}} becomes $ARGUMENTS. Subfolder git/commit.toml becomes /git:commit. |
| Claude Code rule | Garuda rule | Bash(x:*) and Bash(x *) → bash(x*); Read(p) → read_file(p); Edit/Write/MultiEdit(p) → edit_file(p) and write_file(p); WebFetch(domain:h) → web_fetch(h); mcp__… stays. Others: skipped. |
OpenCode permission |
Garuda rules | bash, edit, read, webfetch; allow and deny only (ask is Garuda’s default). |
| Instruction files | – | Not copied. The init turn reads them and carries over what still applies into AGENTS.md. |
Not imported, with a line in the preview: hooks (another format), personal permission rules (Garuda has
project settings only). Claude Code skills (.claude/skills, ~/.claude/skills) need no import: Garuda reads
them where they are (0.5, see skills.md).
The plan: new files only
Section titled “The plan: new files only”buildPlan(items, {root, home, defaults}):
- MCP servers: one new
mcp.jsonper scope (~/.garuda/mcp.json,.garuda/mcp.json). If the file exists, its servers are listed as “add it there by hand”. The first server with a name wins. - Commands: one new file each, in
~/.garuda/commands/or.garuda/commands/. A built-in name or an existing file: skipped. - Rules and defaults: a new
.garuda/settings.jsonwithexecutor: "auto", the rules,undo.enabled: trueandlsp.enabled: false. If the file exists: the rules are listed as “add it there by hand”. .gitignore: the only change to an existing file. Garuda adds the missing lines of.garuda/sessions/,.garuda/index/,.garuda/evals/under a comment.
applyPlan creates new files with the wx flag: a file that appeared after the preview is not replaced.
The preview groups the lines per agent: + goes (with ! notes), - does not (with the reason). Then it
lists the files, new or append.
- Init only reads other agents’ files. It starts no server and runs no command, except
git initafter a yes. - Imported project servers and commands are ordinary project files. They still need consent the first
time (
TrustStore), like any project server or command. - Secrets are not copied (see env values). Headers are not copied.
- A project URL server must be https on a public address, the same rule as
.garuda/mcp.json.
The folder and the prompt
Section titled “The folder and the prompt”folderKind(root):
code: a build file at the root (package.json,pom.xml,pyproject.toml,go.mod…), or a source file up to three folder levels deep.notes: files, but no code.empty: no files.- Dot folders and dependency folders (
node_modules,target,dist…) are skipped. At most 5 000 entries.
initPrompt(kind, otherFiles):
code: read with glob, grep and read_file; do not change code; create or improve AGENTS.md with “Build and test”, “Structure”, “Conventions”, “Notes”; only checked facts; no secrets.emptyandnotes: ask the user what to build (language, build tool, test tool), with defaults; no files in this turn; then AGENTS.md and an offer of a skeleton.- Other agents’ instruction files are named, so the model reads them.
In plan mode, /init adds a line: the init turn can only read; /build lets it write AGENTS.md.
Web search (0.14): when ~/.garuda/search.json has a claude section and no use, init asks once
which web search to use (Claude’s search, the other provider when there is one, or none) and saves the
answer as use (saveSearchUse). It is a user setting, for every project.
initTip(root) for the chat start banner: another agent’s files and no .garuda → “Found files of …”;
no AGENTS.md, CLAUDE.md or GARUDA.md → a hint to type /init; else nothing.
Entry points
Section titled “Entry points”garuda init [-m model]: starts the chat with/initas the first line (firstInput), in the Ink chat and in the plain REPL./initin the chat:Runtime.init(signal)runs steps 1 and 2 and returns the report and the prompt; the chat runs the prompt as a turn.
test/init.test.ts: each conversion; a folder with files of all seven agents (servers, commands, rules,
instructions, skipped items, no secret in the output); broken files; a private project URL; the plan
(the written files load with loadMcpConfig, loadCommands and parseSettings with no problems);
new files only (existing files unchanged, .gitignore lines added once); duplicate names; a file that
appears after the plan; folderKind, initTip and initPrompt; runInit with yes and no (git init runs
through the HostExecutor); /init through runCommand; garuda init in the plain REPL.