<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nisit Sirimarnkit</title>
    <description>The latest articles on DEV Community by Nisit Sirimarnkit (@nisit15).</description>
    <link>https://dev.to/nisit15</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F408531%2Fcc1c9a4d-369a-4515-add7-e1f78a42294e.jpeg</url>
      <title>DEV Community: Nisit Sirimarnkit</title>
      <link>https://dev.to/nisit15</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nisit15"/>
    <language>en</language>
    <item>
      <title>Garudust: A Self-Improving AI Agent Runtime Built in Rust</title>
      <dc:creator>Nisit Sirimarnkit</dc:creator>
      <pubDate>Wed, 13 May 2026 08:31:13 +0000</pubDate>
      <link>https://dev.to/nisit15/garudust-a-self-improving-ai-agent-runtime-built-in-rust-1j09</link>
      <guid>https://dev.to/nisit15/garudust-a-self-improving-ai-agent-runtime-built-in-rust-1j09</guid>
      <description>&lt;p&gt;WELCOME Garudian!!!&lt;/p&gt;

&lt;p&gt;Most AI agent frameworks share the same two problems: they're heavy to deploy, and they forget everything the moment a session ends.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Garudust&lt;/strong&gt; takes a different approach. It's a self-hostable AI agent runtime written entirely in Rust — a single ~10 MB binary that starts in under 20 milliseconds, remembers what you teach it across sessions, and gets smarter with every conversation.&lt;/p&gt;

&lt;p&gt;No Python runtime. No Docker required for local use. No cloud dependency.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Current release: v0.2.8&lt;/strong&gt; — released 12 May 2025. The project moved from v0.1.0 to v0.2.8 in under two weeks, so it's moving fast.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What Makes Garudust Different?
&lt;/h2&gt;

&lt;p&gt;There's no shortage of AI agent frameworks. Here's why Garudust stands out:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Garudust&lt;/th&gt;
&lt;th&gt;Python-based agents&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Binary size&lt;/td&gt;
&lt;td&gt;~10 MB&lt;/td&gt;
&lt;td&gt;100–500 MB (with deps)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cold start&lt;/td&gt;
&lt;td&gt;&amp;lt; 20 ms&lt;/td&gt;
&lt;td&gt;2–10+ seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memory&lt;/td&gt;
&lt;td&gt;Persistent across sessions&lt;/td&gt;
&lt;td&gt;Usually in-memory only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Self-improvement&lt;/td&gt;
&lt;td&gt;Built-in skill learning loop&lt;/td&gt;
&lt;td&gt;Manual, if at all&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-platform&lt;/td&gt;
&lt;td&gt;Telegram, Discord, Slack, LINE, WhatsApp, Matrix, HTTP&lt;/td&gt;
&lt;td&gt;Varies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LLM backends&lt;/td&gt;
&lt;td&gt;Any OpenAI-compatible + Bedrock&lt;/td&gt;
&lt;td&gt;Varies&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The self-improvement loop is what makes it genuinely different. When Garudust discovers a repeatable multi-step workflow during a session, it writes a skill file automatically. Next time you ask for the same thing, it already knows how to do it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Architecture at a Glance
&lt;/h2&gt;

&lt;p&gt;Garudust is a multi-crate Rust workspace. Every concern is its own crate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;crates/
  garudust-core        Shared traits &amp;amp; types — zero I/O
  garudust-transport   LLM adapters (Anthropic, OpenRouter, Bedrock, Ollama, vLLM, …)
  garudust-tools       Tool registry + built-in toolsets
  garudust-memory      FileMemoryStore (markdown) + SessionDb (SQLite + FTS5)
  garudust-agent       Agent run loop, context compressor, prompt builder
  garudust-platforms   Telegram, Discord, Slack, LINE, WhatsApp, Matrix, Webhook
  garudust-cron        Cron scheduler
  garudust-gateway     axum HTTP gateway — /chat, /chat/stream, /chat/ws, /metrics

bin/
  garudust             CLI: interactive TUI, one-shot, setup, doctor, config
  garudust-server      Headless: all platforms + HTTP + cron in one process
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This composable design means you can add a new tool, platform adapter, or LLM transport without touching anything outside the relevant crate. Most contributions are under 100 lines.&lt;/p&gt;




&lt;h2&gt;
  
  
  Getting Started in 3 Minutes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Install
&lt;/h3&gt;

&lt;p&gt;Download a pre-built binary from &lt;a href="https://github.com/garudust-org/garudust-agent/releases/latest" rel="noopener noreferrer"&gt;GitHub Releases&lt;/a&gt; — no Rust required:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xzf&lt;/span&gt; garudust-&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="nt"&gt;-x86_64-unknown-linux-musl&lt;/span&gt;.tar.gz
&lt;span class="nb"&gt;sudo mv &lt;/span&gt;garudust garudust-server /usr/local/bin/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or install directly from crates.io:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo &lt;span class="nb"&gt;install &lt;/span&gt;garudust garudust-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or build from source (requires Rust 1.75+):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/garudust-org/garudust-agent
&lt;span class="nb"&gt;cd &lt;/span&gt;garudust-agent
cargo build &lt;span class="nt"&gt;--release&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configure
&lt;/h3&gt;

&lt;p&gt;Run the setup wizard — it walks you through provider selection and saves your API key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;garudust setup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Garudust supports: &lt;strong&gt;Anthropic, OpenRouter, AWS Bedrock, Ollama, vLLM&lt;/strong&gt;, or any OpenAI-compatible endpoint. Swap providers with a single env var — no code changes needed.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The wizard pre-fills existing values and masks secrets. Press Enter to keep a value unchanged — a small detail that makes re-configuration much less painful.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Chat
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;garudust   &lt;span class="c"&gt;# interactive TUI&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or run a one-shot task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;garudust &lt;span class="s2"&gt;"summarise the git log from the last 7 days into a changelog"&lt;/span&gt;
garudust &lt;span class="nt"&gt;--model&lt;/span&gt; anthropic/claude-opus-4-7 &lt;span class="s2"&gt;"review this PR for security issues"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Persistent Memory
&lt;/h2&gt;

&lt;p&gt;This is the feature that changes how you work with the agent day to day.&lt;/p&gt;

&lt;p&gt;Garudust automatically saves facts to &lt;code&gt;~/.garudust/memory/&lt;/code&gt; — preferences, project conventions, corrections you make:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You: always format JSON with 2-space indent
Agent: Got it — I'll use 2-space indent for JSON from now on.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next session starts with that preference already loaded. You never repeat yourself.&lt;/p&gt;

&lt;p&gt;A built-in nudge fires every few iterations during long tasks, prompting the agent to persist new facts before the session ends:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# ~/.garudust/config.yaml&lt;/span&gt;
&lt;span class="na"&gt;nudge_interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;   &lt;span class="c1"&gt;# inject memory reminder every 5 LLM iterations (0 = off)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Memory is also protected from prompt injection — recalled facts are wrapped in &lt;code&gt;&amp;lt;untrusted_memory&amp;gt;&lt;/code&gt; tags so the model treats them as data, not instructions.&lt;/p&gt;

&lt;p&gt;What gets saved:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Preferences&lt;/strong&gt; — output format, language, tone, tool choices&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Project details&lt;/strong&gt; — paths, configs, conventions, known quirks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Corrections&lt;/strong&gt; — anything you tell the agent to stop doing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What does &lt;em&gt;not&lt;/em&gt; get saved: session logs, task progress, one-off details. Only facts that will matter in future sessions.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Skill System
&lt;/h2&gt;

&lt;p&gt;Skills are reusable instruction sets stored as plain Markdown files in &lt;code&gt;~/.garudust/skills/&lt;/code&gt;. They're hot-reloaded on every call — edit a file and the next message picks up the change immediately.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/.garudust/skills/
  git-workflow/SKILL.md
  daily-standup/SKILL.md
  rust-code-review/SKILL.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Skills are created automatically
&lt;/h3&gt;

&lt;p&gt;When Garudust discovers a multi-step workflow, it writes the skill itself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You: write a skill for reviewing Rust PRs
Agent: [calls write_skill]
       Saved to ~/.garudust/skills/rust-code-review/SKILL.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Skills stay up to date
&lt;/h3&gt;

&lt;p&gt;The skill reflection pipeline (v0.2.0) automatically updates skills after complex tasks. If steps are outdated or wrong, the agent patches the file — no manual maintenance required.&lt;/p&gt;

&lt;h3&gt;
  
  
  Skill-level tool permissions (v0.2.1)
&lt;/h3&gt;

&lt;p&gt;Each skill declares exactly which tools it's allowed to use via frontmatter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;git-workflow&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Opinionated Git commit and PR workflow&lt;/span&gt;
&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1.0.0&lt;/span&gt;
&lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;terminal&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;read_file&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;write_file&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

Always write conventional commits. Run tests before pushing.
Open a draft PR first, then mark ready when CI is green.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This limits the blast radius of any skill — it can't call tools it hasn't declared.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install skills from the hub (v0.2.5)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;garudust skill &lt;span class="nb"&gt;install &lt;/span&gt;facebook-workflow
garudust skill list
garudust skill uninstall facebook-workflow
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Skills pull from &lt;a href="https://github.com/garudust-org/garudust-hub" rel="noopener noreferrer"&gt;garudust-hub&lt;/a&gt; and install their required tools automatically. If the tool needs a runtime (&lt;code&gt;python3&lt;/code&gt;, &lt;code&gt;node&lt;/code&gt;, etc.) that isn't on PATH, you get a warning immediately at install time — not a silent failure at run time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Multi-Platform Gateway
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;garudust-server&lt;/code&gt; runs HTTP, all platform adapters, and cron jobs in a single process. Set the relevant env vars and start the server — every adapter runs together.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;Required env var(s)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Telegram&lt;/td&gt;
&lt;td&gt;&lt;code&gt;TELEGRAM_TOKEN&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Discord&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DISCORD_TOKEN&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Slack&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;SLACK_BOT_TOKEN&lt;/code&gt; + &lt;code&gt;SLACK_APP_TOKEN&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LINE&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;LINE_CHANNEL_SECRET&lt;/code&gt; + &lt;code&gt;LINE_CHANNEL_ACCESS_TOKEN&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WhatsApp&lt;/td&gt;
&lt;td&gt;Meta Cloud API credentials&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Matrix&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;MATRIX_HOMESERVER&lt;/code&gt; + &lt;code&gt;MATRIX_USER&lt;/code&gt; + &lt;code&gt;MATRIX_PASSWORD&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTTP&lt;/td&gt;
&lt;td&gt;Always-on at &lt;code&gt;POST /chat&lt;/code&gt; — no token needed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;TELEGRAM_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;123:ABC &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;LINE_CHANNEL_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;abc... &lt;span class="se"&gt;\&lt;/span&gt;
garudust-server &lt;span class="nt"&gt;--anthropic-key&lt;/span&gt; sk-ant-...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One binary, every channel.&lt;/p&gt;




&lt;h2&gt;
  
  
  HTTP API
&lt;/h2&gt;

&lt;p&gt;Three transport modes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Blocking&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:3000/chat &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"message": "write a haiku about Rust"}'&lt;/span&gt;

&lt;span class="c"&gt;# Streaming (Server-Sent Events)&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:3000/chat/stream &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"message": "explain async/await in 3 sentences"}'&lt;/span&gt;

&lt;span class="c"&gt;# WebSocket: ws://localhost:3000/chat/ws&lt;/span&gt;
&lt;span class="c"&gt;# Send: {"message": "..."} → Receive: text chunks ... {"done": true}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prometheus-compatible metrics at &lt;code&gt;/metrics&lt;/code&gt;. Health check at &lt;code&gt;/health&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Cron Scheduling
&lt;/h2&gt;

&lt;p&gt;Run agent tasks on a schedule with a single env var:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;GARUDUST_CRON_JOBS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"0 9 * * *=Write a morning briefing and save to ~/briefing.md"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
garudust-server &lt;span class="nt"&gt;--anthropic-key&lt;/span&gt; sk-ant-...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Combined with the skill system and a platform adapter, this becomes a powerful automation layer — daily social media posts, standup summaries, report generation, or any workflow you can describe in plain text.&lt;/p&gt;




&lt;h2&gt;
  
  
  Built-in Tools
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;th&gt;Since&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;web_fetch&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fetch any URL (capped at 512 KB)&lt;/td&gt;
&lt;td&gt;v0.1.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;web_search&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Brave Search API; falls back to DuckDuckGo&lt;/td&gt;
&lt;td&gt;v0.1.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;browser&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Control Chrome via CDP — navigate, click, screenshot, JS&lt;/td&gt;
&lt;td&gt;v0.1.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;read_file&lt;/code&gt; / &lt;code&gt;write_file&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Filesystem access&lt;/td&gt;
&lt;td&gt;v0.1.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;terminal&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run shell commands (sandboxed via Docker, opt-in)&lt;/td&gt;
&lt;td&gt;v0.1.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;memory&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Persistent key-value store&lt;/td&gt;
&lt;td&gt;v0.1.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;session_search&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Full-text search across past conversations (SQLite FTS5)&lt;/td&gt;
&lt;td&gt;v0.1.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;delegate_task&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Spawn parallel sub-agents; results returned in order&lt;/td&gt;
&lt;td&gt;v0.1.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;list_directory&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Browse filesystem&lt;/td&gt;
&lt;td&gt;v0.2.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;http_request&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Make REST API calls directly without curl&lt;/td&gt;
&lt;td&gt;v0.2.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pdf_read&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Extract text from PDF files&lt;/td&gt;
&lt;td&gt;v0.2.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;write_skill&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create or update skills on the fly&lt;/td&gt;
&lt;td&gt;v0.1.0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  MCP Support
&lt;/h3&gt;

&lt;p&gt;Connect any &lt;a href="https://modelcontextprotocol.io" rel="noopener noreferrer"&gt;MCP&lt;/a&gt; server in &lt;code&gt;~/.garudust/config.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;mcp_servers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;filesystem&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx&lt;/span&gt;
    &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-y"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@modelcontextprotocol/server-filesystem"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/tmp"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx&lt;/span&gt;
    &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-y"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@modelcontextprotocol/server-postgres"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;postgresql://localhost/mydb"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Security
&lt;/h2&gt;

&lt;p&gt;A few things worth highlighting for anyone self-hosting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Terminal sandbox&lt;/strong&gt; — shell commands run inside a hardened Docker container (&lt;code&gt;--cap-drop ALL&lt;/code&gt;, &lt;code&gt;--security-opt no-new-privileges:true&lt;/code&gt;, tmpfs &lt;code&gt;/tmp&lt;/code&gt;). Opt-in via &lt;code&gt;terminal_sandbox: docker&lt;/code&gt; in config.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ConstitutionalApprover&lt;/strong&gt; — LLM-based approval gate for commands, not regex that can be bypassed via shell obfuscation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DNS TOCTOU fix&lt;/strong&gt; — a custom &lt;code&gt;SafeResolver&lt;/code&gt; closes the gap where a hostname could resolve to a private IP between the check and the actual request.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompt injection protection&lt;/strong&gt; — recalled memory is wrapped in &lt;code&gt;&amp;lt;untrusted_memory&amp;gt;&lt;/code&gt; tags so the model treats it as data, not instructions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Structured audit log&lt;/strong&gt; — every tool call is logged at INFO level with session ID, tool name, and arguments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LLM retry with exponential backoff&lt;/strong&gt; — transient 429/5xx errors are retried automatically.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Usage Footer
&lt;/h2&gt;

&lt;p&gt;Every completed task appends a summary (added in v0.2.2):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[5 iter | 24657in 689out tok | ~$0.003 @ Qwen3-14B-AWQ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Iterations, token counts, estimated cost, and model — useful for understanding what tasks actually cost at scale.&lt;/p&gt;




&lt;h2&gt;
  
  
  Self-Hosted LLM Support
&lt;/h2&gt;

&lt;p&gt;If you run your own LLM (vLLM, Ollama), Garudust connects with zero friction:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Ollama&lt;/span&gt;
&lt;span class="nv"&gt;OLLAMA_BASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost:11434
&lt;span class="nv"&gt;GARUDUST_MODEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;llama3.2

&lt;span class="c"&gt;# vLLM&lt;/span&gt;
&lt;span class="nv"&gt;VLLM_BASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost:8000/v1
&lt;span class="nv"&gt;VLLM_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;token-abc123
&lt;span class="nv"&gt;GARUDUST_MODEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Qwen/Qwen3-14B-AWQ
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No cloud required. Your data stays local.&lt;/p&gt;




&lt;h2&gt;
  
  
  Docker
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"OPENROUTER_API_KEY=sk-or-..."&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .env
docker compose up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The compose file is included in the repo.&lt;/p&gt;




&lt;h2&gt;
  
  
  Contributing
&lt;/h2&gt;

&lt;p&gt;Good first issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;New tool&lt;/strong&gt; — wrap any CLI or API as a &lt;code&gt;Tool&lt;/code&gt; impl in &lt;code&gt;garudust-tools&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;New platform&lt;/strong&gt; — implement &lt;code&gt;PlatformAdapter&lt;/code&gt; (Signal, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improve TUI&lt;/strong&gt; — multi-line input, syntax highlighting, mouse support&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tests&lt;/strong&gt; — integration, property, snapshot
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/garudust-org/garudust-agent
&lt;span class="nb"&gt;cd &lt;/span&gt;garudust-agent
cargo build
cargo &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--workspace&lt;/span&gt;
cargo clippy &lt;span class="nt"&gt;--workspace&lt;/span&gt; &lt;span class="nt"&gt;--all-targets&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;-W&lt;/span&gt; clippy::all &lt;span class="nt"&gt;-W&lt;/span&gt; clippy::pedantic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Repo:&lt;/strong&gt; &lt;a href="https://github.com/garudust-org/garudust-agent" rel="noopener noreferrer"&gt;github.com/garudust-org/garudust-agent&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skill &amp;amp; Tool Hub:&lt;/strong&gt; &lt;a href="https://github.com/garudust-org/garudust-hub" rel="noopener noreferrer"&gt;github.com/garudust-org/garudust-hub&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;crates.io:&lt;/strong&gt; &lt;a href="https://crates.io/crates/garudust" rel="noopener noreferrer"&gt;crates.io/crates/garudust&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;docs.rs:&lt;/strong&gt; &lt;a href="https://docs.rs/garudust-agent" rel="noopener noreferrer"&gt;docs.rs/garudust-agent&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Latest release:&lt;/strong&gt; &lt;a href="https://github.com/garudust-org/garudust-agent/releases/latest" rel="noopener noreferrer"&gt;v0.2.8&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;License:&lt;/strong&gt; MIT&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Built by developers who got tired of agent frameworks that weigh a gigabyte, forget everything, and require three cloud services to run "locally."&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>ai</category>
      <category>agents</category>
      <category>selfhosted</category>
    </item>
    <item>
      <title>Build an AI-Powered Auto-Post Bot for Facebook with Garudust</title>
      <dc:creator>Nisit Sirimarnkit</dc:creator>
      <pubDate>Wed, 13 May 2026 08:07:57 +0000</pubDate>
      <link>https://dev.to/nisit15/build-an-ai-powered-auto-post-bot-for-facebook-with-garudust-430</link>
      <guid>https://dev.to/nisit15/build-an-ai-powered-auto-post-bot-for-facebook-with-garudust-430</guid>
      <description>&lt;p&gt;Social media managers spend hours crafting posts, finding images, and hitting "publish." What if a single terminal command could do all of that — research a topic, write an engaging post, generate a matching image, and publish it to your Facebook Page automatically?&lt;/p&gt;

&lt;p&gt;That's exactly what &lt;strong&gt;Garudust&lt;/strong&gt; does. It's an open-source AI agent written in Rust that connects to any OpenAI-compatible LLM (local or cloud) and runs multi-step workflows through a simple skill system.&lt;/p&gt;

&lt;p&gt;In this guide, you'll set up Garudust and run a fully automated Facebook post workflow from scratch.&lt;/p&gt;




&lt;h2&gt;
  
  
  What You'll Build
&lt;/h2&gt;

&lt;p&gt;One command → one full Facebook post:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;garudust &lt;span class="s2"&gt;"use skill facebook-workflow, post about AI news today, page_id=YOUR_PAGE_ID"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🔍 &lt;strong&gt;Search the web&lt;/strong&gt; for recent news on your topic&lt;/li&gt;
&lt;li&gt;📄 &lt;strong&gt;Read and summarize&lt;/strong&gt; the best article it finds&lt;/li&gt;
&lt;li&gt;🎨 &lt;strong&gt;Generate a matching image&lt;/strong&gt; with overlay text&lt;/li&gt;
&lt;li&gt;✍️ &lt;strong&gt;Write a detailed post&lt;/strong&gt; with hashtags in your target language&lt;/li&gt;
&lt;li&gt;📢 &lt;strong&gt;Publish everything&lt;/strong&gt; to your Facebook Page — no manual steps&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before you start, make sure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Rust (stable)&lt;/strong&gt; — install via &lt;a href="https://rustup.rs" rel="noopener noreferrer"&gt;rustup.rs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;Facebook Page&lt;/strong&gt; you manage&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;Facebook Developer App&lt;/strong&gt; with &lt;code&gt;pages_manage_posts&lt;/code&gt; permission&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;LLM endpoint&lt;/strong&gt; — local (vLLM / Ollama) or cloud (OpenRouter / Anthropic)&lt;/li&gt;
&lt;li&gt;Optional: A &lt;strong&gt;Hugging Face token&lt;/strong&gt; for AI image generation&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 1 — Install Garudust
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo &lt;span class="nb"&gt;install &lt;/span&gt;garudust
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run the interactive setup wizard:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;garudust setup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates two files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;~/.garudust/config.yaml&lt;/code&gt; — non-secret settings&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;~/.garudust/.env&lt;/code&gt; — API keys and tokens&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 2 — Configure Your LLM
&lt;/h2&gt;

&lt;p&gt;Garudust separates settings from secrets. Open &lt;code&gt;~/.garudust/config.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Non-secret settings — safe to share or commit&lt;/span&gt;
&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Qwen/Qwen3-14B-AWQ&lt;/span&gt;    &lt;span class="c1"&gt;# or gpt-4o, claude-3-5-sonnet, etc.&lt;/span&gt;
&lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vllm&lt;/span&gt;                &lt;span class="c1"&gt;# vllm | ollama | anthropic | openrouter&lt;/span&gt;
&lt;span class="na"&gt;base_url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://localhost:8000/v1&lt;/span&gt;

&lt;span class="na"&gt;context_window&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;32768&lt;/span&gt;
&lt;span class="na"&gt;compression&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;threshold_fraction&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.65&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add your secrets to &lt;code&gt;~/.garudust/.env&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Secrets only — never put model or URL here&lt;/span&gt;
&lt;span class="nv"&gt;VLLM_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-vllm-key
&lt;span class="nv"&gt;HF_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;hf_xxxxxxxxxxxx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Design principle:&lt;/strong&gt; &lt;code&gt;config.yaml&lt;/code&gt; holds everything that isn't a secret (model name, provider, URLs, behavior tuning). &lt;code&gt;.env&lt;/code&gt; holds only API keys. This makes it trivial to share your config without leaking credentials.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Using a cloud provider instead? Here's how each maps:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Provider&lt;/th&gt;
&lt;th&gt;config.yaml&lt;/th&gt;
&lt;th&gt;.env&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;vLLM (local)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;provider: vllm&lt;/code&gt; + &lt;code&gt;base_url&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;VLLM_API_KEY&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ollama (local)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;provider: ollama&lt;/code&gt; + &lt;code&gt;base_url&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;em&gt;(none needed)&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anthropic&lt;/td&gt;
&lt;td&gt;&lt;code&gt;provider: anthropic&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ANTHROPIC_API_KEY&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenRouter&lt;/td&gt;
&lt;td&gt;&lt;code&gt;provider: openrouter&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;OPENROUTER_API_KEY&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Step 3 — Get a Facebook Page Access Token
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="https://developers.facebook.com" rel="noopener noreferrer"&gt;developers.facebook.com&lt;/a&gt; → &lt;strong&gt;My Apps&lt;/strong&gt; → create a new app&lt;/li&gt;
&lt;li&gt;Add the &lt;strong&gt;Facebook Login&lt;/strong&gt; product&lt;/li&gt;
&lt;li&gt;Open the &lt;strong&gt;Graph API Explorer&lt;/strong&gt;, select your app and your Page&lt;/li&gt;
&lt;li&gt;Generate a token with these permissions:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pages_manage_posts&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pages_read_engagement&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Exchange it for a &lt;strong&gt;long-lived Page Access Token&lt;/strong&gt; (valid 60 days)&lt;/li&gt;
&lt;li&gt;Add it to your &lt;code&gt;.env&lt;/code&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;FACEBOOK_ACCESS_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;EAAxxxxxxxxxxxxxxxx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Your Page ID is visible in Page Settings under &lt;strong&gt;About&lt;/strong&gt;, or in the Page URL.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Step 4 — Install the Skill and Tools
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;garudust skill &lt;span class="nb"&gt;install &lt;/span&gt;facebook-workflow
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This pulls the skill from garudust-hub and automatically installs the required tools: &lt;code&gt;facebook_post&lt;/code&gt; and &lt;code&gt;generate_image&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Verify everything is in place:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;garudust skill list
&lt;span class="c"&gt;# ✓ facebook-workflow  v3.0.0&lt;/span&gt;

garudust tool list
&lt;span class="c"&gt;# ✓ facebook_post&lt;/span&gt;
&lt;span class="c"&gt;# ✓ generate_image&lt;/span&gt;
&lt;span class="c"&gt;# ✓ web_search&lt;/span&gt;
&lt;span class="c"&gt;# ✓ web_fetch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 5 — Run Your First Auto-Post
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;garudust &lt;span class="s2"&gt;"use skill facebook-workflow, research latest AI news, write a detailed post, generate an image, post to page_id=831735183365530"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Watch the agent work through each step:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[web_search]     searching: AI news 2025...
[web_fetch]      fetching top result...
[generate_image] creating /tmp/fb_post_image.png...
[facebook_post]  publishing to page 831735183365530...

Posted — ID: 831735183365530_122126910027165465
[5 iter | 24657in 689out @ Qwen3-14B-AWQ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Your post is live. ✅&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  How It Works Under the Hood
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;facebook-workflow&lt;/code&gt; skill is a plain Markdown file at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/.garudust/skills/facebook-workflow/SKILL.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It guides the agent through four steps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Step 1 — Research   →  web_search + web_fetch (1 search, 1 fetch)
Step 2 — Image      →  generate_image (1024×576, with overlay text)
Step 3 — Post       →  facebook_post (page_id + message + image_path)
Step 4 — Report     →  confirm post_id or surface the error
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each step explicitly tells the model which tool to call and when. This prevents weak models from staying in "text mode" and skipping tool calls entirely — a common failure mode in multi-step agent workflows.&lt;/p&gt;

&lt;h3&gt;
  
  
  Automatic Context Management
&lt;/h3&gt;

&lt;p&gt;For models with small context windows (e.g. 27K tokens), Garudust handles overflow automatically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compresses conversation history when it reaches &lt;strong&gt;65%&lt;/strong&gt; of the context limit&lt;/li&gt;
&lt;li&gt;Caps &lt;code&gt;max_tokens&lt;/code&gt; at &lt;code&gt;context_window / 8&lt;/code&gt; to always leave room for input&lt;/li&gt;
&lt;li&gt;Retries with a smaller output budget (&lt;code&gt;/16&lt;/code&gt; → &lt;code&gt;/32&lt;/code&gt;) if the first attempt still overflows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You don't need to think about tokens — just set &lt;code&gt;context_window&lt;/code&gt; in &lt;code&gt;config.yaml&lt;/code&gt; and the agent handles the rest.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 6 — Customize the Post Format
&lt;/h2&gt;

&lt;p&gt;The post format is defined directly in the skill file. Edit it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nano ~/.garudust/skills/facebook-workflow/SKILL.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Find the post format section and adjust it to your style:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gs"&gt;**Post format (minimum 200 words):**&lt;/span&gt;

[hook — 1–2 attention-grabbing sentences, use a question or surprising fact]

[background — why this matters, 2–3 sentences of context]

[main content — facts, figures, and deep details from research, 3–4 sentences]

[real example — a company, product, or case study, 2–3 sentences]

[impact &amp;amp; trends — what this means for the future, 2–3 sentences]

[call to action — ask for opinions or suggest next steps, 1–2 sentences]

&lt;span class="gh"&gt;#hashtag1 #hashtag2 #hashtag3 #hashtag4 #hashtag5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Want posts in English instead of Thai? Change the language note. Want longer posts? Raise the minimum word count. The model will follow whatever format you define here.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 7 — Automate with a Daily Cron Job
&lt;/h2&gt;

&lt;p&gt;Create a shell script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# /usr/local/bin/daily-ai-post.sh&lt;/span&gt;
&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
garudust &lt;span class="s2"&gt;"use skill facebook-workflow, latest AI technology news, write a detailed post, generate an image, post to page_id=YOUR_PAGE_ID"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.garudust/post.log 2&amp;gt;&amp;amp;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make it executable and add it to cron:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x /usr/local/bin/daily-ai-post.sh
crontab &lt;span class="nt"&gt;-e&lt;/span&gt;

&lt;span class="c"&gt;# Post every day at 9:00 AM&lt;/span&gt;
0 9 &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; /usr/local/bin/daily-ai-post.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it — &lt;strong&gt;fully automated daily posts with zero manual work.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Troubleshooting
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;required tool facebook_post not called&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Model skipped the tool call&lt;/td&gt;
&lt;td&gt;Retry, or switch to a stronger model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;HTTP 400 context overflow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Prompt too long for context window&lt;/td&gt;
&lt;td&gt;Reduce &lt;code&gt;context_window&lt;/code&gt; or set a smaller &lt;code&gt;web_fetch&lt;/code&gt; limit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;FACEBOOK_ACCESS_TOKEN not set&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Missing secret&lt;/td&gt;
&lt;td&gt;Add to &lt;code&gt;~/.garudust/.env&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Post published but has no image&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;generate_image&lt;/code&gt; failed silently&lt;/td&gt;
&lt;td&gt;Check &lt;code&gt;HF_TOKEN&lt;/code&gt; in &lt;code&gt;.env&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Token expired after 60 days&lt;/td&gt;
&lt;td&gt;Short-lived token used&lt;/td&gt;
&lt;td&gt;Regenerate a long-lived Page Access Token&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  What to Try Next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multiple languages&lt;/strong&gt; — add &lt;code&gt;"write in English"&lt;/code&gt; or &lt;code&gt;"write in Japanese"&lt;/code&gt; to your task&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Topic rotation&lt;/strong&gt; — pass a topics array in a shell script and pick one per day&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multiple pages&lt;/strong&gt; — loop over page IDs to cross-post automatically&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom image styles&lt;/strong&gt; — edit the &lt;code&gt;generate_image&lt;/code&gt; prompt in the skill to match your brand&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;p&gt;Garudust is fully open source:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Agent:&lt;/strong&gt; &lt;a href="https://github.com/garudust-org/garudust-agent" rel="noopener noreferrer"&gt;github.com/garudust-org/garudust-agent&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skill &amp;amp; Tool Hub:&lt;/strong&gt; &lt;a href="https://github.com/garudust-org/garudust-hub" rel="noopener noreferrer"&gt;github.com/garudust-org/garudust-hub&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The hub has community-contributed skills and tools — install any of them with a single &lt;code&gt;garudust skill install&lt;/code&gt; command. If you build something useful, &lt;strong&gt;contributions are welcome.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>automation</category>
      <category>facebook</category>
      <category>rust</category>
    </item>
  </channel>
</rss>
