Garudust Agent
Your AI agent. Your server. Your rules.
A self-improving AI agent runtime written in Rust β ~10 MB binary, no runtime dependencies. Chat in the terminal, reply across 7 platforms, open the web dashboard, run the desktop app, or expose a REST + WebSocket API. Connect any MCP server, swap LLM providers with one env var. No telemetry. No lock-in.
Quick Start
01 β Install
curl -fsSL https://raw.githubusercontent.com/garudust-org/garudust-agent/main/scripts/install.sh | sh
macOS & Linux, any arch (ARM, Raspberry Pi, WSL). Windows: irm .../scripts/install.ps1 | iex. Override with GARUDUST_VERSION / GARUDUST_BIN_DIR.
Grab a pre-built binary from GitHub Releases:
| OS | Architecture | Binary |
|---|---|---|
| macOS | Apple Silicon (M1/M2/M3/M4) | garudust-*-aarch64-apple-darwin.tar.gz |
| macOS | Intel | garudust-*-x86_64-apple-darwin.tar.gz |
| Linux | x86_64 | garudust-*-x86_64-unknown-linux-musl.tar.gz |
| Linux | ARM64 (Raspberry Pi 4/5, Jetson) | garudust-*-aarch64-unknown-linux-musl.tar.gz |
| Windows | x86_64 | garudust-*-x86_64-pc-windows-msvc.zip |
Or build from source (Rust 1.87+): git clone https://github.com/garudust-org/garudust-agent && cargo build --release
02 β Configure
garudust setup # interactive wizard β picks provider, writes config.yaml + .env
Or set your key directly in ~/.garudust/.env (e.g. ANTHROPIC_API_KEY=sk-ant-...). See LLM Providers for all supported keys.
03 β Run
garudust # interactive TUI
garudust "summarise git log" # one-shot task
garudust --hint fast "check this" # route to a cheaper model
garudust-server --port 3000 # headless REST + WebSocket server (+ web dashboard, see below)
docker compose up -d
# Management subcommands
garudust setup # interactive first-time setup wizard
garudust doctor # check environment and configuration
garudust config show # view current configuration
garudust config set <key> <value> # set a configuration value
garudust model [<name>] # get or switch the active model
# Script tools
garudust tool list # list installed + available hub tools
garudust tool install <name> # install a tool from the hub
garudust tool uninstall <name> # remove an installed tool
garudust tool update [<name>] # update one tool (omit to update all)
# Skills
garudust skill list # list installed + available hub skills
garudust skill install <source> # install from hub / GitHub / URL / well-known
garudust skill uninstall <name> # remove an installed skill
garudust skill update [<name>] # update one skill (omit to update all)
garudust skill validate [<path>] # validate SKILL.md frontmatter
Desktop app & web dashboard
The recommended way to use Garudust with a UI is the native desktop app β a pure-Rust (egui) app with the agent embedded in-process (no webview, no separate server). Just download and run.
β¬ Download Garudust Desktop
π macOS Β Β·Β πͺ Windows Β Β·Β π§ Linux (AppImage) Β Β·Β π¦ Debian/Ubuntu (.deb)
macOS is a universal build (Intel + Apple Silicon). Other archs / versions: all releases
| OS | Install |
|---|---|
| macOS | open the .dmg, drag Garudust to Applications |
| Windows 10/11 | run the .exe installer |
| Linux | chmod +x Garudust_*.AppImage && ./Garudust_*.AppImage |
| Debian / Ubuntu | sudo dpkg -i Garudust_*.deb |
Builds are not yet code-signed, so on first launch macOS Gatekeeper (right-click β Open) and Windows SmartScreen (More info β Run anyway) will warn β expected for unsigned apps.
On first run, set your LLM key on the Secrets page (or in ~/.garudust/.env).
The Secrets page is masked + write-only; the agent runs inside the app itself.
Build from source: cargo run -p garudust-desktop-native --release (see
apps/desktop-native/README.md).
Prefer the browser? The same UI (Rust/Leptos β WASM) is
served by the server with the web-ui feature:
cd web && trunk build --release # one-time: cargo install trunk + rustup target add wasm32-unknown-unknown
cargo run -p garudust-server --features web-ui --port 3000 # β open http://localhost:3000
Features
πͺΆ Tiny footprint β ~10 MB statically linked binary, < 20 ms cold start, zero runtime dependencies. Runs on a Raspberry Pi without Docker.
π§ Self-improving β remembers your preferences and facts across every session. Automatically writes reusable skills after complex multi-step workflows. Cross-session goals stay injected until you mark them done β you never repeat yourself.
π 24 LLM providers, one config line β Anthropic, OpenAI, Gemini, Groq, Mistral, DeepSeek, Ollama, AWS Bedrock, vLLM, and 15 more. Route tasks to cheaper models with --hint, rotate fallback keys automatically on auth failure.
π‘ 7 platforms in one process β Telegram, Discord, Slack, Matrix, LINE, WhatsApp, Webhook. Per-platform RBAC, mention gate, per-user session isolation β each adapter activates the moment its token is in .env.
β‘ Parallel tool execution β independent tool calls run concurrently; conflict-prone calls serialized by key. 15+ built-in tools: web search, file I/O, browser automation (CDP), terminal, RAG, sub-agent delegation. Connect any MCP server or drop a custom script tool in any language.
π Secure by design β three sandbox modes for the terminal tool: direct host, Docker container, or SSH remote host. Hardline blocks on the most destructive commands regardless of sandbox. Approval modes (auto / smart / deny) gate destructive operations. Secrets are redacted from all tool output before the model sees them.
π Headless API β garudust-server exposes /chat, /stream, and a WebSocket endpoint β embed in any app or script. Cron-scheduled autonomous tasks run without a user present.
π₯οΈ Web dashboard & native desktop app β a Rust/Leptos (WASM) dashboard served straight from the binary (web-ui feature) for the browser, plus a pure-Rust native egui desktop app with the agent embedded in-process (DMG / EXE / AppImage / deb). No JS/TS; secrets stay masked and server-side.
Platforms
All adapters run in the same garudust-server process. Set the token in ~/.garudust/.env and the adapter activates automatically.
LLM Providers
Set providers.default.name in config.yaml and the corresponding key in ~/.garudust/.env:
| Provider | name |
.env key |
|---|---|---|
| Anthropic | anthropic |
ANTHROPIC_API_KEY |
| OpenAI | openai |
OPENAI_API_KEY |
| Google Gemini | gemini |
GEMINI_API_KEY |
| Groq | groq |
GROQ_API_KEY |
| Mistral | mistral |
MISTRAL_API_KEY |
| DeepSeek | deepseek |
DEEPSEEK_API_KEY |
| xAI (Grok) | xai |
XAI_API_KEY |
| OpenRouter | openrouter |
OPENROUTER_API_KEY |
| AWS Bedrock | bedrock |
AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY |
| Ollama | ollama |
(none β add url: for custom endpoint) |
| vLLM | vllm |
VLLM_API_KEY |
| ThaiLLM | thaillm |
THAILLM_API_KEY |
| Together AI | together |
TOGETHER_API_KEY |
| Fireworks AI | fireworks |
FIREWORKS_API_KEY |
| Cerebras | cerebras |
CEREBRAS_API_KEY |
| Perplexity | perplexity |
PERPLEXITY_API_KEY |
| Cohere | cohere |
COHERE_API_KEY |
| NVIDIA NIM | nvidia |
NVIDIA_API_KEY |
| Alibaba DashScope | alibaba |
DASHSCOPE_API_KEY |
| ByteDance Doubao | doubao |
ARK_API_KEY |
| Zhipu AI (GLM) | zhipu |
ZHIPU_API_KEY |
| Moonshot (Kimi) | moonshot |
MOONSHOT_API_KEY |
| Baidu ERNIE | baidu |
QIANFAN_API_KEY |
| Any OpenAI-compat | (omit name:, set url: in profile) |
relevant key |
Fallback keys: set LLM_FALLBACK_API_KEYS=key2,key3 in .env β rotated automatically on auth failure.
Architecture
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β bin/garudust (CLI) bin/garudust-server (Daemon) β
ββββββββββββββββββββββ¬ββββββββββββββββββββββββββ¬ββββββββββββββββββββββββ
β β
β ββββββββββββββββ΄ββββββββββββββββββββββββ
β β garudust-gateway (server-only) β
β β POST /chat Β· POST /stream Β· GET /ws β
β β RBAC Β· /join Β· /invite Β· Metrics β
β ββββββββββββββββββββββββββββββββββββββββ€
β β garudust-platforms (server-only) β
β β Telegram Β· Discord Β· Slack β
β β LINE Β· Matrix Β· WhatsApp Β· Webhook β
β ββββββββββββββββββββββββββββββββββββββββ€
β β garudust-cron (server-only) β
β β cron-scheduled autonomous tasks β
β ββββββββββββββββ¬ββββββββββββββββββββββββ
β β
βΌ βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β garudust-agent (run-loop) β
β load memory β build prompt β LLM call β tool dispatch β repeat β
ββββββββ¬βββββββββββββββ¬ββββββββββββββββββ¬ββββββββββββββββββββββββββββββ
βΌ βΌ βΌ
garudust- garudust- garudust-
transport tools memory
(24 LLMs + (built-in + (memory.md +
key rotation) hub + MCP) SQLite + RAG)
garudust-core β shared types Β· config Β· traits (used by every crate above)
Configuration
Secrets β ~/.garudust/.env. Everything else β ~/.garudust/config.yaml.
~/.garudust/.env
# LLM provider β set one (auto-detected from env when no config.yaml)
ANTHROPIC_API_KEY=sk-ant-...
# OPENAI_API_KEY=sk-...
# GEMINI_API_KEY=AIza...
# GROQ_API_KEY=gsk_...
# Fallback keys β rotated automatically on auth failure
# LLM_FALLBACK_API_KEYS=sk-ant-backup1,sk-ant-backup2
# Platform adapters β set only what you use
TELEGRAM_TOKEN=123456789:AAFxxx
DISCORD_TOKEN=<bot-token>
SLACK_BOT_TOKEN=xoxb-...
SLACK_APP_TOKEN=xapp-...
LINE_CHANNEL_TOKEN=<channel-access-token>
LINE_CHANNEL_SECRET=<32-char-hex>
WHATSAPP_ACCESS_TOKEN=EAAxxxxx
WHATSAPP_PHONE_NUMBER_ID=123456789012345
WHATSAPP_VERIFY_TOKEN=my_verify_token
# Search (optional β falls back to DuckDuckGo)
BRAVE_SEARCH_API_KEY=BSA...
SERPER_API_KEY=...
# Gateway auth
GARUDUST_API_KEY=my-gateway-secret
~/.garudust/config.yaml
providers:
default:
name: anthropic # see LLM Providers table above for all 24 options
key: ${ANTHROPIC_API_KEY}
model: claude-sonnet-4-6
security:
approval_mode: smart # auto | smart | deny
terminal_sandbox: none # none | docker | ssh
rate_limit_rpm: ~ # per-IP limit (~ = unlimited)
rate_limit_rpm_per_user: ~ # per-(platform, user_id) limit
# ββ SSH sandbox (terminal_sandbox: ssh) ββββββββββββββββββββββββββββββ
# ssh_host: "192.168.1.50" # required
# ssh_user: "pi" # optional β defaults to current OS user
# ssh_port: 22 # optional β default 22
# ssh_key_path: ~/.ssh/garudust_pi # optional β uses ~/.ssh/id_* if unset
# ssh_jump_host: "bastion.example.com" # optional β ProxyJump for hosts behind NAT
# ssh_remote_cwd: "/home/pi/scripts" # optional β cd here before every command
# ssh_options: ["IdentitiesOnly=yes"] # optional β extra -o flags (escape hatch)
# Route a single task to a different model without changing the default:
routing:
fast: groq-fast/llama-3.1-8b-instant
# then: garudust --hint fast "quick question"
# Use a cheap model for background skill-reflection (defaults to main model):
reflection_model: groq/llama-3.1-8b-instant
# Conversation window per session β pairs of (user, assistant) turns (default 20):
max_history_pairs: 20
For the full config reference (cron, MCP, RBAC, compression, etc.) see CONTRIBUTING.md.
Tools
Built-in, no configuration needed:
web_fetch Β· web_search Β· http_request Β· browser (CDP) Β· read_file Β· write_file Β· list_directory Β· terminal Β· memory Β· session_search Β· delegate_task Β· skill_view Β· write_skill Β· doc_ingest Β· doc_search
Hub β community tools and skills from garudust-hub:
garudust tool install hash_text # script tool β ~/.garudust/tools/hash_text/
garudust tool install read_qr
garudust skill install weather # Markdown instruction, no subprocess
garudust skill install fetch-title
MCP β connect any Model Context Protocol server:
mcp_servers:
- name: filesystem
command: npx
args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
Custom tools β drop a tool.yaml + script in ~/.garudust/tools/<name>/. Any language. See garudust-hub for examples.
Access Control
Role-based access via roles: in config.yaml. The first person to DM the bot is auto-promoted to admin when no users are assigned yet.
roles:
default_role: member
definitions:
admin: { approval_mode: auto }
member: { approval_mode: smart, allowed_toolsets: [web, files, memory], denied_tools: [bash] }
readonly: { approval_mode: deny }
users:
telegram:
"123456789": admin
Runtime commands: /whoami Β· /join [code] Β· /invite <role> [max_uses] Β· /role list|add|approve|remove
Production: set
terminal_sandbox: docker(local container) orterminal_sandbox: ssh(remote host) to sandbox shell execution, andmax_delegation_depth: 0to prevent sub-agent chains.
Note: setting
platform.session_per_user: falsecauses all users to share one conversation context. The server logs aWARNat startup as a reminder. Only safe for single-user deployments.
Terminal Sandbox
The terminal tool supports three execution backends:
| Mode | terminal_sandbox |
Runs on | Requires |
|---|---|---|---|
| Direct host | none |
Local machine | Nothing |
| Docker container | docker |
Isolated container | Docker daemon |
| Remote SSH host | ssh |
Any host with sshd | SSH key auth |
All modes share the same hardline blocks (fork bomb, rm -rf /, mkfs, etc.) and the same approval gate β the sandbox only controls where the command runs.
SSH Sandbox
Commands are forwarded via the system ssh binary to a remote host. Useful for managing a remote server, Raspberry Pi, or build machine without exposing any port to the internet β the agent SSHes out, the remote host just needs port 22 open.
Config fields (all under security: in config.yaml):
| Field | Type | Default | Description |
|---|---|---|---|
ssh_host |
string | β | Required. Remote hostname or IP |
ssh_user |
string | current OS user | Login username |
ssh_port |
integer | 22 |
SSH port |
ssh_key_path |
path | ~/.ssh/id_* |
Private key file |
ssh_jump_host |
string | β | ProxyJump bastion (user@host:port) for hosts behind NAT |
ssh_remote_cwd |
string | β | cd <dir> && prepended to every command; must be an absolute path with no shell metacharacters (e.g. /home/pi/scripts) |
ssh_options |
list | [] |
Extra -o key=value flags (appended after hardened defaults) |
Environment variable overrides β no config.yaml required:
GARUDUST_TERMINAL_SANDBOX=ssh
GARUDUST_SSH_HOST=192.168.1.50
GARUDUST_SSH_USER=pi
GARUDUST_SSH_PORT=22
GARUDUST_SSH_KEY_PATH=/home/user/.ssh/garudust_pi
Minimal working example β Raspberry Pi behind a home router:
security:
terminal_sandbox: ssh
ssh_host: "192.168.1.50"
ssh_user: "pi"
ssh_key_path: ~/.ssh/garudust_pi
With a bastion β Pi is reachable only through a public jump server:
security:
terminal_sandbox: ssh
ssh_host: "pi.internal"
ssh_user: "pi"
ssh_key_path: ~/.ssh/garudust_pi
ssh_jump_host: "bastion.example.com"
Security properties applied automatically:
BatchMode=yesβ no interactive prompts; fails immediately if key auth is rejectedStrictHostKeyChecking=accept-newβ auto-trusts first contact, rejects changed host keys (MITM protection)ConnectTimeoutcapped at 30 s β no indefinite TCP hangsServerAliveInterval=10 ServerAliveCountMax=3β detects dead connections in ~30 s rather than hanging until the command timeout fires--before the command β prevents a command starting with-from being misread as an SSH flagenv_clear()before spawningsshβ API keys and secrets never reach the remote hostssh_remote_cwdis validated as a safe absolute path before use β values containing shell metacharacters (;&|`$><quotes, whitespace, etc.) are rejected at command time, not silently forwarded to the remote shellssh_optionsare appended after hardened defaults βBatchModeandStrictHostKeyCheckingcannot be overridden by caller config
Memory & Skills
The agent saves everything it learns to ~/.garudust/memory/ and loads it at the start of every session β you never need to repeat yourself. Repeating workflows are automatically written as reusable skills in ~/.garudust/skills/ after auto_skill_threshold iterations. Set reflection_model in config.yaml to use a cheaper model for this background pass and keep costs down.
Contributing
Garudust is Rust and designed to be extended. Pick your area:
| Area | Where | Effort |
|---|---|---|
| Hub tool or skill | garudust-hub β tool.yaml + script |
Low β no Rust needed |
| Bug reports / docs | Issues | Minimal |
| New LLM provider | crates/garudust-transport/src/ β impl ProviderTransport (2 methods) |
Medium |
| New platform adapter | crates/garudust-platforms/src/ β impl PlatformAdapter (2 methods) |
Medium |
| Built-in tool | crates/garudust-tools/src/toolsets/ β impl Tool, register in ToolRegistry::new() |
Medium (~100 lines) |
| Core features | Agent loop, memory, compression, gateway | High |
git clone https://github.com/garudust-org/garudust-agent
cd garudust-agent
git config core.hooksPath .githooks # enable pre-push checks (fmt + tests)
cargo build && cargo test --workspace && cargo clippy --workspace
Step-by-step guides for each area: CONTRIBUTING.md
Community: Discord Β· Issues Β· Discussions Β· dev.to/garudust
License
MIT β see LICENSE.
No comments yet
Be the first to share your take.