<?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>Forem: Garudust</title>
    <description>The latest articles on Forem by Garudust (@garudust).</description>
    <link>https://forem.com/garudust</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%2F668da519-e26f-4bb7-95a5-82a60f527c22.png</url>
      <title>Forem: Garudust</title>
      <link>https://forem.com/garudust</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/garudust"/>
    <language>en</language>
    <item>
      <title>Cron &amp; Scheduled Tasks in Garudust Agent — Autonomous Agents That Run Without You</title>
      <dc:creator>Garudust</dc:creator>
      <pubDate>Thu, 21 May 2026 07:17:45 +0000</pubDate>
      <link>https://forem.com/garudust/cron-scheduled-tasks-in-garudust-autonomous-agents-that-run-without-you-5ecg</link>
      <guid>https://forem.com/garudust/cron-scheduled-tasks-in-garudust-autonomous-agents-that-run-without-you-5ecg</guid>
      <description>&lt;p&gt;Most AI agents wait. They sit idle until a human types something, respond, then go back to waiting.&lt;/p&gt;

&lt;p&gt;Garudust Agent can be different. With &lt;code&gt;garudust-cron&lt;/code&gt;, you schedule tasks using standard cron syntax — the agent wakes up, runs a full LLM loop with all its tools, and goes back to sleep. No human required.&lt;/p&gt;

&lt;p&gt;This post shows you exactly how to configure it, with the correct syntax pulled straight from the source.&lt;/p&gt;




&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;garudust-cron&lt;/code&gt; is a crate within the Garudust workspace. When a scheduled trigger fires, it calls &lt;code&gt;agent.run(task)&lt;/code&gt; — the same code path as a user typing a message. The agent has access to all its configured tools: file read/write, terminal, RAG, web search, and anything else you've enabled.&lt;/p&gt;

&lt;p&gt;Cron runs as part of &lt;code&gt;garudust-server&lt;/code&gt;. There is no separate daemon.&lt;/p&gt;




&lt;h2&gt;
  
  
  Three Ways to Set Up Cron Jobs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. &lt;code&gt;config.yaml&lt;/code&gt; — Permanent, survives restarts
&lt;/h3&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;cron&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;9&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;1-5"&lt;/span&gt;   &lt;span class="c1"&gt;# weekdays at 09:00 (server timezone)&lt;/span&gt;
      &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Write&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;morning&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;briefing&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;append&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;it&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;~/briefing.md"&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;18&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;5"&lt;/span&gt;    &lt;span class="c1"&gt;# Fridays at 18:00&lt;/span&gt;
      &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Summarise&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;this&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;week's&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;git&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;commits&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;save&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;~/weekly.md"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;CronJob&lt;/code&gt; has exactly two fields: &lt;code&gt;schedule&lt;/code&gt; and &lt;code&gt;task&lt;/code&gt;. Nothing else.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;schedule&lt;/code&gt; uses &lt;strong&gt;6-field&lt;/strong&gt; cron syntax (seconds first):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;┌───────── &lt;span class="n"&gt;second&lt;/span&gt; (&lt;span class="m"&gt;0&lt;/span&gt;–&lt;span class="m"&gt;59&lt;/span&gt;)
│ ┌─────── &lt;span class="n"&gt;minute&lt;/span&gt; (&lt;span class="m"&gt;0&lt;/span&gt;–&lt;span class="m"&gt;59&lt;/span&gt;)
│ │ ┌───── &lt;span class="n"&gt;hour&lt;/span&gt; (&lt;span class="m"&gt;0&lt;/span&gt;–&lt;span class="m"&gt;23&lt;/span&gt;)
│ │ │ ┌─── &lt;span class="n"&gt;day&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;month&lt;/span&gt; (&lt;span class="m"&gt;1&lt;/span&gt;–&lt;span class="m"&gt;31&lt;/span&gt;)
│ │ │ │ ┌─ &lt;span class="n"&gt;month&lt;/span&gt; (&lt;span class="m"&gt;1&lt;/span&gt;–&lt;span class="m"&gt;12&lt;/span&gt;)
│ │ │ │ │ ┌ &lt;span class="n"&gt;day&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;week&lt;/span&gt; (&lt;span class="m"&gt;0&lt;/span&gt;–&lt;span class="m"&gt;6&lt;/span&gt;, &lt;span class="n"&gt;Sun&lt;/span&gt;=&lt;span class="m"&gt;0&lt;/span&gt;)
│ │ │ │ │ │
&lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;9&lt;/span&gt; * * &lt;span class="m"&gt;1&lt;/span&gt;-&lt;span class="m"&gt;5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Timezone follows the server process — set your system timezone before starting &lt;code&gt;garudust-server&lt;/code&gt; if needed.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. CLI flag or environment variable — One-off / Docker
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# CLI flag — comma-separated "cron_expr=task" pairs&lt;/span&gt;
garudust-server &lt;span class="nt"&gt;--cron-jobs&lt;/span&gt; &lt;span class="s2"&gt;"0 0 9 * * *=Write morning briefing,0 0 18 * * 5=Weekly summary"&lt;/span&gt;

&lt;span class="c"&gt;# Or via environment variable in ~/.garudust/.env&lt;/span&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 0 9 * * *=Write morning briefing"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These take precedence over &lt;code&gt;config.yaml&lt;/code&gt; when both are set.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Runtime via chat — No restart needed
&lt;/h3&gt;

&lt;p&gt;Once the server is running, you (or any admin) can create jobs live by asking the agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You:   Create a cron job that runs every day at 7am to check disk usage
       and send me an alert if any partition is above 80%.

Agent: [uses cron_create tool]
       Created cron job 'disk_check' with schedule: 0 0 7 * * *
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;code&gt;cron_create&lt;/code&gt; uses &lt;strong&gt;6-field&lt;/strong&gt; cron syntax (seconds first): &lt;code&gt;sec min hour dom month dow&lt;/code&gt;&lt;br&gt;
Same format as &lt;code&gt;config.yaml&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Format&lt;/th&gt;
&lt;th&gt;Where used&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6-field&lt;/td&gt;
&lt;td&gt;everywhere (&lt;code&gt;config.yaml&lt;/code&gt;, &lt;code&gt;--cron-jobs&lt;/code&gt;, env var, &lt;code&gt;cron_create&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0 0 9 * * 1-5&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Runtime jobs are &lt;strong&gt;not persisted&lt;/strong&gt; — they disappear on server restart. Add them to &lt;code&gt;config.yaml&lt;/code&gt; for permanent schedules.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Manage runtime jobs:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You:   List all active cron jobs.
Agent: - [disk_check]  schedule: 0 0 7 * * *  task: Check disk usage...  created: 2025-05-21 07:00 UTC

You:   Delete the disk_check job.
Agent: Cron job 'disk_check' removed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Memory Maintenance (Bonus)
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;CronConfig&lt;/code&gt; has two extra fields specifically for automatic memory housekeeping:&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;cron&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;9&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
      &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Morning&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;briefing"&lt;/span&gt;

  &lt;span class="c1"&gt;# Consolidate and deduplicate memory entries&lt;/span&gt;
  &lt;span class="na"&gt;memory_consolidation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;3&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;   &lt;span class="c1"&gt;# daily at 03:00&lt;/span&gt;

  &lt;span class="c1"&gt;# Expire stale memory entries (based on memory_expiry settings)&lt;/span&gt;
  &lt;span class="na"&gt;memory_expiry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;4&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;0"&lt;/span&gt;          &lt;span class="c1"&gt;# weekly on Sunday at 04:00&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These run lightweight maintenance tasks — no LLM call required.&lt;/p&gt;




&lt;h2&gt;
  
  
  Practical Examples
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Morning Briefing
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;cron&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;8&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;1-5"&lt;/span&gt;
      &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="s"&gt;Write a morning briefing covering: (1) any new files in ~/inbox/,&lt;/span&gt;
        &lt;span class="s"&gt;(2) a summary of yesterday's ~/logs/app.log errors,&lt;/span&gt;
        &lt;span class="s"&gt;(3) today's date and day of week.&lt;/span&gt;
        &lt;span class="s"&gt;Save the result to ~/briefing/$(date +%Y-%m-%d).md.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Log Monitoring
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;cron&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*/15&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;   &lt;span class="c1"&gt;# every 15 minutes&lt;/span&gt;
      &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="s"&gt;Check /var/log/app/error.log for entries in the last 15 minutes.&lt;/span&gt;
        &lt;span class="s"&gt;If there are more than 10 errors, append a summary to ~/alerts/errors.log.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Weekly Git Summary
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;cron&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;17&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;5"&lt;/span&gt;   &lt;span class="c1"&gt;# Fridays at 17:00&lt;/span&gt;
      &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="s"&gt;Run git log --since="1 week ago" --oneline in ~/project/,&lt;/span&gt;
        &lt;span class="s"&gt;summarise what changed by area, and save to ~/reports/weekly.md.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Sending Results to Telegram
&lt;/h3&gt;

&lt;p&gt;Cron jobs have no built-in delivery mechanism — the agent writes to files or uses tools. To send to Telegram, write it into the task prompt:&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;cron&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;9&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
      &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="s"&gt;Write a morning briefing (top 3 priorities for today, weather summary).&lt;/span&gt;
        &lt;span class="s"&gt;Then send it to Telegram chat ID 123456789 using the send_message tool.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent calls &lt;code&gt;send_message&lt;/code&gt; itself. The chat ID must be hardcoded in the task or retrievable from a file the agent can read.&lt;/p&gt;




&lt;h2&gt;
  
  
  Disabling Cron Tools
&lt;/h2&gt;

&lt;p&gt;If you want to prevent the agent from creating or deleting jobs at runtime, disable the toolset:&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;disabled_toolsets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;cron&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Config-file jobs still run — only the &lt;code&gt;cron_create&lt;/code&gt; / &lt;code&gt;cron_list&lt;/code&gt; / &lt;code&gt;cron_delete&lt;/code&gt; runtime tools are disabled.&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&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;&lt;code&gt;config.yaml&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;
&lt;code&gt;--cron-jobs&lt;/code&gt; / env var&lt;/th&gt;
&lt;th&gt;Runtime (&lt;code&gt;cron_create&lt;/code&gt;)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cron syntax&lt;/td&gt;
&lt;td&gt;6-field&lt;/td&gt;
&lt;td&gt;6-field&lt;/td&gt;
&lt;td&gt;6-field&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Persists across restarts&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Requires restart to activate&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;cron_list&lt;/code&gt; shows it&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Start with &lt;code&gt;config.yaml&lt;/code&gt; for anything you want running reliably. Use runtime jobs for experiments or tasks you only need for the current server session.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Garudust Agent&lt;/strong&gt; — &lt;a href="https://github.com/garudust-org/garudust-agent" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://github.com/garudust-org/garudust-agent/releases" rel="noopener noreferrer"&gt;Releases&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>ai</category>
      <category>automation</category>
      <category>devops</category>
    </item>
    <item>
      <title>Chat With Your Documents Using Garudust Agent — No Vector Database Required</title>
      <dc:creator>Garudust</dc:creator>
      <pubDate>Thu, 21 May 2026 06:47:49 +0000</pubDate>
      <link>https://forem.com/garudust/chat-with-your-documents-using-garudust-agent-no-vector-database-required-1m61</link>
      <guid>https://forem.com/garudust/chat-with-your-documents-using-garudust-agent-no-vector-database-required-1m61</guid>
      <description>&lt;p&gt;Most RAG tutorials start the same way: &lt;em&gt;"First, install a vector database…"&lt;/em&gt; Then come the embedding models, the chunking strategies, the similarity thresholds. By the time you can ask a question about a PDF, you've deployed three services and written 200 lines of boilerplate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Garudust Agent&lt;/strong&gt; takes a different path. RAG is built in — backed by SQLite FTS5 with a trigram tokenizer. No vector database. No embedding API calls. Drop a PDF (or TXT, CSV, Markdown, JSON) into the conversation and start asking questions in seconds.&lt;/p&gt;




&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;p&gt;When you ingest a document, Garudust:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Extracts text (native PDF parser, no external tools)&lt;/li&gt;
&lt;li&gt;Splits it into chunks (≤ 800 chars, paragraph-aware)&lt;/li&gt;
&lt;li&gt;Indexes chunks into an FTS5 virtual table with &lt;code&gt;tokenize = 'trigram'&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When you ask a question, &lt;code&gt;doc_search&lt;/code&gt; runs a full-text query against the index and feeds the top matching chunks to the LLM as context. That's the whole pipeline — one SQLite file at &lt;code&gt;~/.garudust/state.db&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The trigram tokenizer means it works on &lt;strong&gt;any language&lt;/strong&gt;, including Thai, Chinese, and Japanese, without any tokenizer configuration.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;RAG is enabled by default. The only thing you need to configure is which directories the agent is allowed to read from:&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;security&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;allowed_read_paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/home/you/documents&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/data/company-docs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. If you want to turn RAG off entirely:&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;disabled_toolsets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;rag&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Your First Ingestion
&lt;/h2&gt;

&lt;p&gt;Start the CLI:&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then tell the agent to ingest a file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You: ingest /home/you/documents/employee-handbook.pdf

Agent: Indexed employee-handbook.pdf — 47 chunks ready for search.
       Preview: "This handbook outlines the policies and procedures for all employees…"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now ask anything:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You: What is the remote work policy?

Agent: According to the employee handbook, remote work is permitted up to 3 days per week
       for roles that do not require on-site presence. Employees must notify their manager
       at least 24 hours in advance and maintain availability during core hours (10am–4pm).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Four RAG 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;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;doc_ingest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Extract and index a file (PDF, TXT, CSV, MD, JSON…)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;doc_search&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Full-text search across all ingested documents&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;doc_list&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List all indexed documents with chunk count and timestamp&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;doc_forget&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Remove one file or clear the entire index&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You never call these directly — the agent decides when to use them based on your question. But knowing they exist helps you understand what's happening.&lt;/p&gt;

&lt;h3&gt;
  
  
  Re-ingesting a file
&lt;/h3&gt;

&lt;p&gt;If a document changes, just ingest it again. The old index for that path is replaced automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  Forgetting a document
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You: Remove the Q1 report from the index.
Agent: Document removed from index.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or clear everything:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You: Clear all indexed documents.
Agent: Removed 5 document(s) from index.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  FTS5 Query Syntax
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;doc_search&lt;/code&gt; supports full FTS5 syntax, which the agent uses automatically when your question benefits from it:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Syntax&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;AND (default)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;remote work policy&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Phrase&lt;/td&gt;
&lt;td&gt;&lt;code&gt;"annual leave"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OR&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vacation OR leave&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NOT&lt;/td&gt;
&lt;td&gt;&lt;code&gt;policy NOT contractor&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prefix&lt;/td&gt;
&lt;td&gt;&lt;code&gt;terminat*&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You don't need to write FTS5 queries yourself — the agent figures this out. But if you want to guide it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You: Search for "termination clause" in the contract documents.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Real-World Use Cases
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Company Knowledge Base
&lt;/h3&gt;

&lt;p&gt;Ingest your onboarding docs, SOPs, and internal wikis. New team members can ask questions in plain language instead of searching through Confluence.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You: ingest /docs/sop-release-process.md
You: What approvals are needed before a hotfix can go to production?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Contract and Legal Review
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You: ingest /legal/vendor-agreement-2025.pdf
You: Does this contract include a limitation of liability clause? What is the cap?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Log Analysis
&lt;/h3&gt;

&lt;p&gt;Ingest a log file and ask questions without writing grep patterns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You: ingest /var/log/app/error.log
You: Which service caused the most errors in the last hour?
You: Are there any database connection timeouts?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Codebase Documentation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You: ingest /project/docs/api-reference.md
You: What parameters does the /auth/refresh endpoint accept?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Ingesting Files Sent via Telegram or LINE
&lt;/h2&gt;

&lt;p&gt;If you're running &lt;code&gt;garudust-server&lt;/code&gt; with a messaging platform, users can send files directly to the bot. Attachments are automatically saved to a temporary path and can be ingested on request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User sends: quarterly-report.pdf (attached)

Agent: I received your file. Would you like me to index it for search?

User: yes

Agent: Indexed quarterly-report.pdf — 83 chunks ready.
       Preview: "Q1 2025 Financial Summary — Total Revenue: $4.2M…"

User: What was the gross margin for Q1?
Agent: According to the report, gross margin for Q1 2025 was 61.3%,
       up from 58.9% in Q4 2024.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Platform attachments (files from Telegram, LINE, Discord, etc.) are always allowed regardless of &lt;code&gt;allowed_read_paths&lt;/code&gt;, since they're written to &lt;code&gt;/tmp/garudust_*&lt;/code&gt; by the platform adapter.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Multiple Documents at Once
&lt;/h2&gt;

&lt;p&gt;You can ingest multiple files and search across all of them in the same session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You: ingest /docs/policy-2024.pdf
You: ingest /docs/policy-2025.pdf
You: What changed in the travel expense policy between 2024 and 2025?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent searches both documents and synthesizes the differences.&lt;/p&gt;

&lt;p&gt;Check what's indexed at any time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You: What documents have you indexed?

Agent: 2 documents indexed:
       - policy-2024.pdf | 34 chunks | ingested 2025-05-21 09:14
       - policy-2025.pdf | 38 chunks | ingested 2025-05-21 09:15
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No semantic search&lt;/strong&gt; — FTS5 is keyword/trigram matching, not embedding similarity. If the document says "annual leave" and you ask about "vacation days," the agent bridges this with its language understanding, but results depend on the LLM's reasoning.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Session-scoped by default&lt;/strong&gt; — The index persists in &lt;code&gt;state.db&lt;/code&gt;, but searches are scoped to the current conversation key. Starting a new session means re-ingesting if you want to query the same files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Text-only&lt;/strong&gt; — Images, tables, and charts inside PDFs are not extracted. Text content only.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&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 RAG&lt;/th&gt;
&lt;th&gt;Vector DB approach&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Setup&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;One config line&lt;/td&gt;
&lt;td&gt;Vector DB + embedding API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Storage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;SQLite (single file)&lt;/td&gt;
&lt;td&gt;Separate service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Languages&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Any (trigram)&lt;/td&gt;
&lt;td&gt;Depends on embedding model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Zero (no embedding calls)&lt;/td&gt;
&lt;td&gt;Per-token embedding cost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Search type&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;FTS5 keyword + LLM reasoning&lt;/td&gt;
&lt;td&gt;Semantic similarity&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Garudust's RAG won't replace a purpose-built vector search pipeline for large-scale production retrieval. But for a developer who wants to ask questions about their documents right now — without running a second service — it's the fastest path from PDF to answer.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Garudust Agent&lt;/strong&gt; — &lt;a href="https://github.com/garudust-org/garudust-agent" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://github.com/garudust-org/garudust-agent/releases" rel="noopener noreferrer"&gt;Releases&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>ai</category>
      <category>rag</category>
      <category>llm</category>
    </item>
    <item>
      <title>ให้ AI พูดภาษาไทยได้ด้วย Garudust Agent + iApp TTS</title>
      <dc:creator>Garudust</dc:creator>
      <pubDate>Tue, 19 May 2026 02:29:43 +0000</pubDate>
      <link>https://forem.com/garudust/aih-ai-phuudphaasaaaithyaiddwy-garudust-agent-iapp-tts-35n2</link>
      <guid>https://forem.com/garudust/aih-ai-phuudphaasaaaithyaiddwy-garudust-agent-iapp-tts-35n2</guid>
      <description>&lt;p&gt;ถ้าคุณใช้ Garudust Agent อยู่แล้ว การเพิ่มความสามารถให้ AI &lt;strong&gt;พูดภาษาไทยออกมาเป็นเสียง&lt;/strong&gt; ทำได้ในไม่กี่ขั้นตอน — ไม่ต้องแก้โค้ดใด ๆ เพราะ Garudust มีระบบ script tool ที่ pluggable อยู่แล้ว&lt;/p&gt;




&lt;h2&gt;
  
  
  TTS คืออะไร และทำไมต้อง iApp
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;TTS (Text-to-Speech)&lt;/strong&gt; คือการแปลงข้อความเป็นเสียงพูด เหมาะกับ use case เช่น&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ตอบกลับผู้ใช้ด้วยเสียงแทนข้อความบน LINE / Telegram&lt;/li&gt;
&lt;li&gt;สร้างไฟล์เสียงสำหรับ podcast / narration อัตโนมัติ&lt;/li&gt;
&lt;li&gt;Accessibility — ผู้ใช้ที่อ่านหน้าจอยาก&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;iApp Technology&lt;/strong&gt; เป็นบริษัทไทยที่มี TTS API รองรับภาษาไทยโดยเฉพาะ เสียงฟังเป็นธรรมชาติ รองรับสูงสุด 10,000 ตัวอักษรต่อ request คิดค่าใช้จ่าย 1 IC ต่อ 400 ตัวอักษร สมัครได้ที่ &lt;a href="https://iapp.co.th" rel="noopener noreferrer"&gt;iapp.co.th&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  ขั้นตอนที่ 1 — ติดตั้ง tts tool จาก Hub
&lt;/h2&gt;

&lt;p&gt;Garudust มี Hub รวม script tool ให้ install ได้ทันที&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;ระบบจะดึง &lt;code&gt;tool.yaml&lt;/code&gt; และ &lt;code&gt;run.py&lt;/code&gt; มาไว้ที่ &lt;code&gt;~/.garudust/tools/tts/&lt;/code&gt; และ register ใน registry อัตโนมัติ&lt;/p&gt;




&lt;h2&gt;
  
  
  ขั้นตอนที่ 2 — เพิ่ม Provider Profile ใน config.yaml
&lt;/h2&gt;

&lt;p&gt;Garudust ใช้ระบบ &lt;strong&gt;provider profile&lt;/strong&gt; จัดการ API endpoint และ key — ไม่ต้อง hardcode ใน script&lt;/p&gt;

&lt;p&gt;เปิด &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;providers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# ... providers ที่มีอยู่แล้ว ...&lt;/span&gt;
  &lt;span class="na"&gt;tts-iapp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://api.iapp.co.th/v3/store/audio/tts&lt;/span&gt;
    &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${IAPP_API_KEY}&lt;/span&gt;

&lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;tts&lt;/span&gt;&lt;span class="pi"&gt;:&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;tts-iapp&lt;/span&gt;   &lt;span class="c1"&gt;# ชี้ไปที่ profile ข้างบน&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Garudust จะ inject &lt;code&gt;GARUDUST_BASE_URL&lt;/code&gt; และ &lt;code&gt;GARUDUST_API_KEY&lt;/code&gt; เข้า script อัตโนมัติตอน runtime&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  ขั้นตอนที่ 3 — เพิ่ม API Key ใน .env
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# ~/.garudust/.env&lt;/span&gt;
&lt;span class="nv"&gt;IAPP_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;iapp_live_xxxxxxxxxxxxxxxx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;รับ key ได้จาก &lt;a href="https://iapp.co.th/dashboard" rel="noopener noreferrer"&gt;iapp.co.th/dashboard&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  ทดสอบผ่าน CLI
&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;"ใช้ tts tool แปลงข้อความว่า สวัสดีครับ ผมคือ Garudust ผู้ช่วย AI ของคุณ แล้วบอก path ไฟล์ที่ได้"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ผลลัพธ์:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;สร้างไฟล์เสียงสำเร็จ
เสียงอยู่ที่: /tmp/tts_88b5bba372dd41a7acc7e37ea75df89b.wav
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เปิดฟัง:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;open /tmp/tts_88b5bba372dd41a7acc7e37ea75df89b.wav
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  เบื้องหลัง — run.py ทำงานยังไง
&lt;/h2&gt;

&lt;p&gt;iApp TTS API คืน &lt;strong&gt;raw PCM&lt;/strong&gt; มาโดยไม่มี WAV header ดังนั้น &lt;code&gt;run.py&lt;/code&gt; จัดการ wrap header ให้เอง:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;pcm_to_wav&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pcm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sample_rate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;24000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;channels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;byte_rate&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sample_rate&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;channels&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;bits&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;
    &lt;span class="n"&gt;block_align&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;channels&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;bits&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;
    &lt;span class="n"&gt;data_size&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pcm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;4sI4s4sIHHIIHH4sI&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;RIFF&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;36&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;data_size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;WAVE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fmt &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;channels&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sample_rate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;byte_rate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;block_align&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bits&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data_size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;pcm&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ผลที่ได้คือ &lt;strong&gt;RIFF WAV 16-bit mono 24kHz&lt;/strong&gt; — เปิดได้กับทุก audio player&lt;/p&gt;




&lt;h2&gt;
  
  
  เปลี่ยน Provider ได้ทันทีโดยไม่แตะโค้ด
&lt;/h2&gt;

&lt;p&gt;นี่คือจุดแข็งของ Garudust provider profile — ถ้าอยากลอง provider อื่นเช่น AIS หรือ local model แค่เพิ่ม profile และเปลี่ยน &lt;code&gt;tools.tts.model&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;providers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;tts-ais&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://your-ais-tts-endpoint/api/tts&lt;/span&gt;
    &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${AIS_TTS_API_KEY}&lt;/span&gt;

&lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;tts&lt;/span&gt;&lt;span class="pi"&gt;:&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;tts-ais&lt;/span&gt;   &lt;span class="c1"&gt;# เปลี่ยนแค่นี้&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;run.py&lt;/code&gt; ไม่ต้องแตะเลย เพราะอ่าน &lt;code&gt;GARUDUST_BASE_URL&lt;/code&gt; และ &lt;code&gt;GARUDUST_API_KEY&lt;/code&gt; จาก profile เสมอ&lt;/p&gt;




&lt;h2&gt;
  
  
  ขั้นต่อไปที่ทำได้
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;LINE voice message&lt;/strong&gt; — เพิ่ม &lt;code&gt;OutboundMessage::Audio&lt;/code&gt; ใน Garudust core แล้วส่งไฟล์ WAV เป็น voice message บน LINE ได้เลย&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto TTS reply&lt;/strong&gt; — สั่งให้ agent เรียก &lt;code&gt;tts&lt;/code&gt; ทุกครั้งที่ตอบ โดย inject ใน system prompt&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speaker selection&lt;/strong&gt; — iApp มีหลายเสียง ตั้ง &lt;code&gt;TTS_SPEAKER_ID&lt;/code&gt; ใน &lt;code&gt;.env&lt;/code&gt; เพื่อเลือกเสียงที่ชอบ&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  สรุป
&lt;/h2&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;คำสั่ง&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ติดตั้ง tool&lt;/td&gt;
&lt;td&gt;&lt;code&gt;garudust tool install tts&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;เพิ่ม profile&lt;/td&gt;
&lt;td&gt;แก้ &lt;code&gt;config.yaml&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;เพิ่ม key&lt;/td&gt;
&lt;td&gt;แก้ &lt;code&gt;~/.garudust/.env&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ใช้งาน&lt;/td&gt;
&lt;td&gt;สั่ง agent พูดภาษาไทย&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Garudust Agent เป็น open source ที่ &lt;a href="https://github.com/garudust-org/garudust-agent" rel="noopener noreferrer"&gt;github.com/garudust-org/garudust-agent&lt;/a&gt; — ติดตามหรือ contribute ได้เลย 🦅&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rust</category>
      <category>tts</category>
      <category>thai</category>
    </item>
    <item>
      <title>10 Things You Can Do With Logs Using Garudust Agent 🦅</title>
      <dc:creator>Garudust</dc:creator>
      <pubDate>Mon, 18 May 2026 08:11:41 +0000</pubDate>
      <link>https://forem.com/garudust/10-things-you-can-do-with-logs-using-garudust-agent-3a7m</link>
      <guid>https://forem.com/garudust/10-things-you-can-do-with-logs-using-garudust-agent-3a7m</guid>
      <description>&lt;h1&gt;
  
  
  10 Things You Can Do With Logs Using Garudust Agent 🦅
&lt;/h1&gt;

&lt;p&gt;Most developers treat logs the same way: something breaks, you &lt;code&gt;grep&lt;/code&gt; for errors, squint at timestamps, and piece together what happened. That's table stakes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/garudust-org/garudust-agent" rel="noopener noreferrer"&gt;Garudust Agent&lt;/a&gt;&lt;/strong&gt; is a self-hostable AI agent runtime written in Rust. Pair it with the &lt;code&gt;log-analyst&lt;/code&gt; skill from &lt;a href="https://github.com/garudust-org/garudust-hub" rel="noopener noreferrer"&gt;garudust-hub&lt;/a&gt;, and your logs become something you can &lt;em&gt;talk to&lt;/em&gt; — and that can &lt;em&gt;act&lt;/em&gt; on your behalf.&lt;/p&gt;

&lt;p&gt;Here are 10 things you can do that go well beyond grepping for &lt;code&gt;ERROR&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Setup in 60 Seconds
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install&lt;/span&gt;
wget &lt;span class="nt"&gt;-qO-&lt;/span&gt; https://github.com/garudust-org/garudust-agent/releases/latest/download/garudust-&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="nt"&gt;-unknown-linux-musl&lt;/span&gt;.tar.gz | &lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xz&lt;/span&gt;
&lt;span class="nb"&gt;sudo mv &lt;/span&gt;garudust garudust-server /usr/local/bin/

&lt;span class="c"&gt;# Configure (picks your LLM provider)&lt;/span&gt;
garudust setup

&lt;span class="c"&gt;# Install the log skill&lt;/span&gt;
garudust skill &lt;span class="nb"&gt;install &lt;/span&gt;log-analyst
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Local GPU?&lt;/strong&gt; Skip the API entirely:&lt;/p&gt;


&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &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="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GARUDUST_MODEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Qwen/Qwen3-8B-AWQ
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  1. 🕵️ Explain &lt;em&gt;Why&lt;/em&gt; an Incident Happened
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;grep&lt;/code&gt; finds &lt;em&gt;what&lt;/em&gt;. Garudust explains &lt;em&gt;why&lt;/em&gt;.&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;"read /var/log/app.log around 2025-05-14 03:22:00 ±10 minutes.
Reconstruct the chain of events that led to the service crash.
What was the root cause?"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent reads the surrounding context — not just the error line — and builds a timeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Timeline reconstruction:
  03:14:22 — Memory usage crossed 80% threshold (first warning)
  03:19:05 — DB connection pool exhausted (upstream pressure)
  03:21:58 — Request queue backed up, workers stalled
  03:22:11 — OOM killer terminated process (root cause)

Root cause: sustained traffic spike + connection pool too small for load
Recommendation: increase pool size from 10 → 25, add circuit breaker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  2. 📊 Generate a Weekly Incident Report
&lt;/h2&gt;

&lt;p&gt;Stop writing incident summaries by hand.&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;"read /var/log/app.log for the past 7 days.
Generate a weekly incident report with:
- Total error count by day
- Top 5 recurring error types
- Mean time between incidents
- Any worsening trends
Format as Markdown."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pipe it to a file, commit it, send it to Slack — whatever fits your workflow:&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;"weekly incident report from /var/log/app.log"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; reports/week-&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%V&lt;span class="si"&gt;)&lt;/span&gt;.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. 🔁 Detect Crash Loops Before They Become Outages
&lt;/h2&gt;

&lt;p&gt;A service that restarts every 4 minutes isn't &lt;em&gt;down&lt;/em&gt; — your uptime monitor won't catch it. But Garudust will.&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;"scan /var/log/syslog for the last 2 hours.
Detect any process that has started and stopped more than 3 times.
Flag it as a crash loop candidate with restart intervals."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⚠️  CRASH LOOP DETECTED: api-worker
    Restarts in last 2h: 7
    Average interval: 16 minutes
    Last restart: 10 minutes ago
    Pattern: always crashes ~2 min after start (initialization failure likely)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. 🌡️ Baseline "Normal" and Alert on Deviations
&lt;/h2&gt;

&lt;p&gt;What if you don't know what an anomaly looks like — only that something &lt;em&gt;feels&lt;/em&gt; off?&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;"compare /var/log/nginx/access.log from last Monday vs this Monday,
same time window 09:00–12:00.
What's statistically different? Flag anything that deviates by more than 2x."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Garudust doesn't need pre-defined rules. It compares distributions and reasons about what changed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Deviations vs. last Monday baseline:
  • 4xx error rate: 0.3% → 4.1%  (13.7x increase) ⚠️
  • Avg response time: 120ms → 380ms  (3.2x increase) ⚠️
  • /api/search endpoint: 2% → 31% of traffic  (unusual spike)

Hypothesis: new client or bot hitting /api/search aggressively
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5. 🔒 Audit Security Events
&lt;/h2&gt;

&lt;p&gt;Spot brute force attempts, suspicious IPs, and unusual access patterns.&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;"analyze /var/log/auth.log from the last 24 hours.
Find:
- Failed login attempts &amp;gt; 5 from the same IP
- Successful logins from IPs with prior failures
- Any logins at unusual hours (outside 08:00–20:00 local time)
- New user accounts created
Summarize as a security audit."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🔴 Brute Force Attempt:
   IP: 185.234.xx.xx — 847 failed SSH attempts in 3 hours
   ⚠️  This IP succeeded once at 03:41 — INVESTIGATE IMMEDIATELY

🟡 Off-hours Logins:
   user: deploy  — login at 02:14 from 10.0.1.55 (internal, but unusual)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  6. 📈 Build a Performance Degradation Timeline
&lt;/h2&gt;

&lt;p&gt;Know exactly &lt;em&gt;when&lt;/em&gt; things started slowing down — not just that they're slow now.&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;"read /var/log/app.log for the past 30 days.
Plot response time trends by week.
Identify the exact date when p95 latency started increasing.
What changed around that time in the logs?"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is invaluable for debugging regressions that crept in silently over weeks.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. 🤖 Auto-Remediate Known Issues
&lt;/h2&gt;

&lt;p&gt;Garudust has a &lt;code&gt;terminal&lt;/code&gt; tool. Combine log analysis with action.&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;"check /var/log/app.log — if you see more than 20 'disk quota exceeded'
errors in the last hour, run: find /tmp -mtime +1 -delete
then report how many files were removed and current disk usage."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or for a service restart:&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;"monitor /var/log/api.log — if the error rate exceeds 15% over 5 minutes,
run: sudo systemctl restart api-service
and report what you did and why."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Garudust's &lt;code&gt;GARUDUST_APPROVAL_MODE&lt;/code&gt; defaults to &lt;code&gt;smart&lt;/code&gt; — it will ask before running destructive commands. Set to &lt;code&gt;auto&lt;/code&gt; only in controlled environments.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  8. 🔍 Trace a Single Request Across Services
&lt;/h2&gt;

&lt;p&gt;Distributed systems scatter a single user request across multiple log files. Garudust can stitch them back together.&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;"find all log entries related to request_id=a3f9c2b1 across these files:
/var/log/gateway.log
/var/log/auth-service.log
/var/log/api.log
/var/log/db-proxy.log
Build a complete trace timeline with latency at each hop."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request trace: a3f9c2b1
  00ms  gateway.log      — request received, routed to auth
  12ms  auth-service.log — token validated
  13ms  api.log          — handler invoked
  891ms api.log          — ⚠️ waiting on DB (unusually long)
  903ms db-proxy.log     — query executed (full table scan detected)
  905ms gateway.log      — response returned  total: 905ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  9. 📝 Generate a &lt;code&gt;CHANGELOG&lt;/code&gt; from Deploy Logs
&lt;/h2&gt;

&lt;p&gt;If your deploy pipeline writes structured logs, you can generate changelogs automatically.&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;"read /var/log/deploy.log for this month.
Extract all deployments: service name, version, timestamp, who deployed.
Format as a CHANGELOG grouped by week, in Keep a Changelog style."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## [Week 20] — 2025-05-12 to 2025-05-18&lt;/span&gt;

&lt;span class="gu"&gt;### Deployed&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**api-service**&lt;/span&gt; v2.4.1 — 2025-05-14 10:32 (alice)
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**worker**&lt;/span&gt; v1.9.0 — 2025-05-16 14:15 (bob)
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**gateway**&lt;/span&gt; v3.1.2 — 2025-05-17 09:00 (alice)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  10. ⏰ Schedule All of the Above
&lt;/h2&gt;

&lt;p&gt;Everything above can run automatically on a cron schedule — no extra infrastructure needed.&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;TELEGRAM_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_token &lt;span class="se"&gt;\&lt;/span&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 * * 1=Read /var/log/app.log last 7 days, generate weekly incident report, send to telegram;
*/15 * * * *=Check /var/log/app.log last 15 minutes for crash loops or error spikes, alert telegram if found;
0 8 * * *=Audit /var/log/auth.log last 24 hours for security anomalies, send daily security digest to telegram
"&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;Three jobs. Zero extra services. No Prometheus, no Grafana, no ELK cluster.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Mental Model Shift
&lt;/h2&gt;

&lt;p&gt;Traditional log tooling asks you to define rules upfront:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Alert me when error rate &amp;gt; 5%"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Garudust lets you ask questions in plain language — &lt;em&gt;after&lt;/em&gt; something happens, or proactively via cron — and get reasoning, not just matching:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"What went wrong this week, and is it getting worse?"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The difference is the jump from &lt;strong&gt;pattern matching&lt;/strong&gt; to &lt;strong&gt;understanding&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Install the &lt;a href="https://github.com/garudust-org/garudust-hub/tree/main/skills/log-analyst" rel="noopener noreferrer"&gt;&lt;code&gt;log-analyst&lt;/code&gt; skill&lt;/a&gt; and try #1 on your own logs right now&lt;/li&gt;
&lt;li&gt;Write a custom &lt;code&gt;SKILL.md&lt;/code&gt; for your specific log format in &lt;code&gt;~/.garudust/skills/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Contribute your own log tools to &lt;a href="https://github.com/garudust-org/garudust-hub" rel="noopener noreferrer"&gt;garudust-hub&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;🔗 Links:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/garudust-org/garudust-agent" rel="noopener noreferrer"&gt;garudust-org/garudust-agent&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Hub: &lt;a href="https://github.com/garudust-org/garudust-hub" rel="noopener noreferrer"&gt;garudust-org/garudust-hub&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🇹🇭 Thai version: &lt;em&gt;(link after publishing)&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Which of these 10 use cases would save you the most time? Drop a comment — I read every one. 🙌&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>ai</category>
      <category>devops</category>
      <category>log</category>
    </item>
    <item>
      <title>ตรวจจับ Log Anomaly อัตโนมัติด้วย Garudust Agent 🦅</title>
      <dc:creator>Garudust</dc:creator>
      <pubDate>Mon, 18 May 2026 07:19:00 +0000</pubDate>
      <link>https://forem.com/garudust/trwcchcchab-log-anomaly-atonmatidwy-garudust-agent-1d41</link>
      <guid>https://forem.com/garudust/trwcchcchab-log-anomaly-atonmatidwy-garudust-agent-1d41</guid>
      <description>&lt;h1&gt;
  
  
  ตรวจจับ Log Anomaly อัตโนมัติด้วย Garudust Agent 🦅
&lt;/h1&gt;

&lt;p&gt;ถ้าคุณเคยนั่งไล่ดู log ไฟล์ที่ยาวหลายหมื่นบรรทัดเพื่อหาว่า "มันพังตรงไหน" — บทความนี้เขียนมาเพื่อคุณโดยเฉพาะ&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/garudust-org/garudust-agent" rel="noopener noreferrer"&gt;Garudust Agent&lt;/a&gt;&lt;/strong&gt; คือ AI agent runtime ที่เขียนด้วย Rust รองรับการ self-host บน hardware ของคุณเอง และมี skill ชื่อ &lt;code&gt;log-analyst&lt;/code&gt; ใน &lt;a href="https://github.com/garudust-org/garudust-hub" rel="noopener noreferrer"&gt;garudust-hub&lt;/a&gt; ที่ถูกออกแบบมาสำหรับงานนี้โดยตรง&lt;/p&gt;




&lt;h2&gt;
  
  
  🤔 ปัญหาจริงที่นักพัฒนาเจอ
&lt;/h2&gt;

&lt;p&gt;ระบบ production ทุกระบบมี log แต่การไล่อ่าน log ด้วยมือมีปัญหาหลายอย่าง:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ปริมาณมหาศาล&lt;/strong&gt; — log หลักล้านบรรทัดต่อวัน ไม่มีใครอ่านได้หมด&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pattern ซับซ้อน&lt;/strong&gt; — error เดียวกันอาจโผล่ในหลาย format&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;เจอช้า&lt;/strong&gt; — กว่าจะรู้ว่าพัง ผู้ใช้แจ้งมาก่อนแล้ว&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context ขาด&lt;/strong&gt; — รู้ว่า error ตรงไหน แต่ไม่รู้ว่า "ก่อนหน้านั้นมีอะไรเกิดขึ้น"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Garudust แก้ปัญหาเหล่านี้ด้วยการให้ LLM อ่านและวิเคราะห์ log แทนคุณ — แบบ real-time หรือ scheduled ก็ได้&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ ติดตั้ง Garudust
&lt;/h2&gt;

&lt;h3&gt;
  
  
  วิธีที่ 1 — ใช้ Pre-built Binary (แนะนำ)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Linux x86_64&lt;/span&gt;
wget https://github.com/garudust-org/garudust-agent/releases/latest/download/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;tar&lt;/span&gt; &lt;span class="nt"&gt;-xzf&lt;/span&gt; garudust-&lt;span class="k"&gt;*&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;h3&gt;
  
  
  วิธีที่ 2 — Build จาก Source (ต้องมี Rust 1.75+)
&lt;/h3&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;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/target/release"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ตั้งค่าเริ่มต้น
&lt;/h3&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;Wizard จะถามว่าใช้ LLM provider ไหน รองรับทั้ง Anthropic, OpenRouter, vLLM (local), Ollama และ AWS Bedrock&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;สำหรับคนที่มี GPU และ self-host:&lt;/strong&gt; ใช้ vLLM กับ model เช่น Qwen3-8B ได้เลยโดยไม่เสียค่า API&lt;/p&gt;


&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &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="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GARUDUST_MODEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Qwen/Qwen3-8B-AWQ
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  📦 ติดตั้ง &lt;code&gt;log-analyst&lt;/code&gt; Skill
&lt;/h2&gt;

&lt;p&gt;Skill คือ instruction set แบบ Markdown ที่บอก agent ว่าต้องทำอะไร เมื่อไหร่ อย่างไร&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 &lt;span class="nb"&gt;install &lt;/span&gt;log-analyst
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;แค่นี้พอ — ครั้งถัดไปที่คุณพูดถึง log, agent จะโหลด skill นี้มาใช้อัตโนมัติ&lt;/p&gt;




&lt;h2&gt;
  
  
  🔍 ใช้งานจริง: วิเคราะห์ Log ทันที
&lt;/h2&gt;

&lt;h3&gt;
  
  
  กรณีที่ 1 — วิเคราะห์ syslog
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;garudust &lt;span class="s2"&gt;"วิเคราะห์ /var/log/syslog 500 บรรทัดล่าสุด หา error pattern ที่ผิดปกติ"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ตัวอย่าง output ที่ได้:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🔍 Log Analysis Report — /var/log/syslog
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

⚠️  ANOMALY DETECTED: Connection timeout spike
    → 47 occurrences ใน 3 นาที (ปกติ &amp;lt; 2/ชั่วโมง)
    → First seen: 14:32:01, Last: 14:35:18
    → Probable cause: Network interface congestion หรือ upstream service down

❌ ERROR Pattern: OOM Killer activated
    → Process: python3 (PID 18423)
    → Memory usage: 7.8GB / 8GB
    → Recommendation: เพิ่ม swap หรือ review memory leak ใน process

✅ ไม่พบ segfault, kernel panic หรือ disk I/O error
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  กรณีที่ 2 — วิเคราะห์ Application Log
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;garudust &lt;span class="s2"&gt;"อ่าน /opt/myapp/logs/app.log แล้วหา:
- Error rate ต่อนาที
- Request ที่ใช้เวลา &amp;gt; 5 วินาที  
- Pattern ที่น่าสงสัย
สรุปเป็นภาษาไทย"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  กรณีที่ 3 — เปรียบเทียบ Log สองช่วงเวลา
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;garudust &lt;span class="s2"&gt;"เปรียบเทียบ /var/log/nginx/access.log ระหว่าง 10:00-11:00 กับ 14:00-15:00 
ว่า error rate ต่างกันไหม และ traffic pattern เปลี่ยนแปลงอย่างไร"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ⏰ Cron: ตรวจ Log อัตโนมัติ ทุก 30 นาที
&lt;/h2&gt;

&lt;p&gt;นี่คือจุดที่ทำให้ Garudust ต่างจากการรัน script ธรรมดา — agent สามารถ &lt;strong&gt;ตัดสินใจเองได้&lt;/strong&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="nv"&gt;GARUDUST_CRON_JOBS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"*/30 * * * *=Read /var/log/app.log last 300 lines, detect ERROR or WARNING anomalies, if severity is HIGH report summary with timestamp and probable cause"&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;h3&gt;
  
  
  แจ้งเตือนผ่าน Telegram อัตโนมัติ
&lt;/h3&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;your_bot_token &lt;span class="se"&gt;\&lt;/span&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;"*/15 * * * *=Check /var/log/app.log for critical errors in last 15 minutes. If error rate exceeds 10 per minute, send alert to telegram with details"&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;blockquote&gt;
&lt;p&gt;Agent จะส่ง message ไปยัง Telegram bot ของคุณเองอัตโนมัติเมื่อเจอ anomaly&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🏭 Use Case จริง: ระบบ Industrial / Edge AI
&lt;/h2&gt;

&lt;p&gt;สำหรับงาน &lt;strong&gt;IoT&lt;/strong&gt; หรือ &lt;strong&gt;Edge AI&lt;/strong&gt; ที่มี log จากเซนเซอร์หรือกล้องวงจรปิด สามารถทำแบบนี้ได้:&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;# ตรวจสอบ log จากระบบ OCR กล้อง factory ทุก 1 ชั่วโมง&lt;/span&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 * * * *=Analyze /opt/vision/logs/ocr_results.log, find rows where confidence_score &amp;lt; 0.6 or recognition_failed = true, count anomaly rate, if &amp;gt; 5% in last hour generate incident report"&lt;/span&gt; &lt;span class="se"&gt;\&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="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;GARUDUST_MODEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Qwen3-8B-AWQ &lt;span class="se"&gt;\&lt;/span&gt;
garudust-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ข้อดีคือรันบน &lt;strong&gt;local GPU&lt;/strong&gt; ได้เลย ไม่ต้องส่ง log ออกไปยัง cloud เหมาะมากสำหรับระบบ industrial ที่ข้อมูลเป็น confidential&lt;/p&gt;




&lt;h2&gt;
  
  
  ✏️ เขียน Skill เองสำหรับ Log Format เฉพาะทาง
&lt;/h2&gt;

&lt;p&gt;ถ้า log ของคุณมี format แปลก หรืออยากให้ agent วิเคราะห์แบบเฉพาะเจาะจง เขียน SKILL.md เองได้ใน &lt;code&gt;~/.garudust/skills/&lt;/code&gt;:&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;factory-log-analyst&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;Analyze industrial machine log from SMARTSense IDA system&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="nn"&gt;---&lt;/span&gt;

เมื่อถูกขอให้วิเคราะห์ log จากระบบ IDA ให้ทำตามนี้:
&lt;span class="p"&gt;
1.&lt;/span&gt; อ่าน log file ด้วย terminal tool
&lt;span class="p"&gt;2.&lt;/span&gt; หา pattern เหล่านี้ที่บ่งบอกปัญหา:
&lt;span class="p"&gt;   -&lt;/span&gt; confidence_score &amp;lt; 0.5 (OCR accuracy ต่ำผิดปกติ)
&lt;span class="p"&gt;   -&lt;/span&gt; frame_drop_rate &amp;gt; 0.1 (กล้องส่งภาพไม่ครบ)
&lt;span class="p"&gt;   -&lt;/span&gt; roi_timeout (พื้นที่ตรวจสอบไม่ response)
&lt;span class="p"&gt;   -&lt;/span&gt; connection_lost (กล้องหลุด)
&lt;span class="p"&gt;3.&lt;/span&gt; คำนวณ:
&lt;span class="p"&gt;   -&lt;/span&gt; Anomaly rate ต่อชั่วโมง
&lt;span class="p"&gt;   -&lt;/span&gt; ROI ที่มีปัญหาบ่อยที่สุด
&lt;span class="p"&gt;4.&lt;/span&gt; สรุปเป็นภาษาไทย ระบุ:
&lt;span class="p"&gt;   -&lt;/span&gt; ความรุนแรง (Critical / Warning / Info)
&lt;span class="p"&gt;   -&lt;/span&gt; เวลาที่เกิด
&lt;span class="p"&gt;   -&lt;/span&gt; สาเหตุที่น่าจะเป็น
&lt;span class="p"&gt;   -&lt;/span&gt; คำแนะนำในการแก้ไข
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🔧 Tool เพิ่มเติมจาก garudust-hub
&lt;/h2&gt;

&lt;p&gt;นอกจาก &lt;code&gt;log-analyst&lt;/code&gt; skill แล้ว ยังมี tools ใน hub ที่ช่วยงาน log ได้:&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;# ติดตั้ง tools ที่มีประโยชน์&lt;/span&gt;
garudust tool &lt;span class="nb"&gt;install &lt;/span&gt;csv_to_json    &lt;span class="c"&gt;# แปลง log CSV → JSON&lt;/span&gt;
garudust tool &lt;span class="nb"&gt;install &lt;/span&gt;file_info      &lt;span class="c"&gt;# เช็ค size/encoding ก่อนอ่าน&lt;/span&gt;
garudust tool &lt;span class="nb"&gt;install &lt;/span&gt;token_count    &lt;span class="c"&gt;# เช็คว่า log ยาวเกิน context ไหม&lt;/span&gt;
garudust tool &lt;span class="nb"&gt;install &lt;/span&gt;extract_urls   &lt;span class="c"&gt;# ดึง URL จาก access log&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ใช้คู่กันในคำสั่งเดียว:&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;"ใช้ file_info ดูขนาดของ /var/log/nginx/error.log ก่อน แล้วถ้าไม่เกิน 100KB ให้วิเคราะห์หา anomaly ทั้งหมดที่เกิดขึ้นวันนี้"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📊 เปรียบเทียบ: Garudust vs วิธีเดิม
&lt;/h2&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;Script ธรรมดา (grep/awk)&lt;/th&gt;
&lt;th&gt;ELK Stack&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Garudust&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ติดตั้ง&lt;/td&gt;
&lt;td&gt;ง่าย&lt;/td&gt;
&lt;td&gt;ซับซ้อน&lt;/td&gt;
&lt;td&gt;ง่าย (binary เดียว)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Resource&lt;/td&gt;
&lt;td&gt;ต่ำ&lt;/td&gt;
&lt;td&gt;สูงมาก (ต้องการ RAM หลาย GB)&lt;/td&gt;
&lt;td&gt;ต่ำ (~10MB binary)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;วิเคราะห์ context&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅ (LLM เข้าใจ context)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;แจ้งเตือนอัตโนมัติ&lt;/td&gt;
&lt;td&gt;ต้องเขียนเอง&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅ built-in&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Self-host&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ภาษาไทย&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;สรุปสาเหตุ&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🚀 เริ่มต้น 5 นาที
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. ติดตั้ง&lt;/span&gt;
wget &lt;span class="nt"&gt;-qO-&lt;/span&gt; https://github.com/garudust-org/garudust-agent/releases/latest/download/garudust-&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="nt"&gt;-unknown-linux-musl&lt;/span&gt;.tar.gz | &lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xz&lt;/span&gt;
&lt;span class="nb"&gt;sudo mv &lt;/span&gt;garudust /usr/local/bin/

&lt;span class="c"&gt;# 2. ตั้งค่า&lt;/span&gt;
garudust setup

&lt;span class="c"&gt;# 3. ติดตั้ง skill&lt;/span&gt;
garudust skill &lt;span class="nb"&gt;install &lt;/span&gt;log-analyst

&lt;span class="c"&gt;# 4. ลองเลย!&lt;/span&gt;
garudust &lt;span class="s2"&gt;"วิเคราะห์ /var/log/syslog 100 บรรทัดล่าสุด หา error ที่น่าสงสัย"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  สรุป
&lt;/h2&gt;

&lt;p&gt;Garudust ไม่ใช่แค่ tool อ่าน log — มันคือ &lt;strong&gt;agent ที่เข้าใจ context&lt;/strong&gt; ของ log และช่วยตัดสินใจว่าอะไรคือ "ปกติ" หรือ "ผิดปกติ" โดยใช้ความสามารถของ LLM&lt;/p&gt;

&lt;p&gt;จุดแข็งที่สำคัญสำหรับ DevOps และ Industrial Engineer คือ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Self-host ได้ 100%&lt;/strong&gt; — ไม่ต้องส่ง log ออก cloud&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;รองรับ local LLM&lt;/strong&gt; — ใช้ vLLM + Qwen/LLaMA บน GPU ของตัวเองได้&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ภาษาไทยได้เลย&lt;/strong&gt; — detect ภาษาอัตโนมัติ ไม่ต้องตั้งค่า&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cron built-in&lt;/strong&gt; — ตั้งตรวจอัตโนมัติได้ทันที&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;🔗 Links:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/garudust-org/garudust-agent" rel="noopener noreferrer"&gt;garudust-org/garudust-agent&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Hub: &lt;a href="https://github.com/garudust-org/garudust-hub" rel="noopener noreferrer"&gt;garudust-org/garudust-hub&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Facebook Community: &lt;a href="https://www.facebook.com/groups/1520306226240762" rel="noopener noreferrer"&gt;Garudust Agent Thailand&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;มีคำถามหรืออยากแลกเปลี่ยนประสบการณ์ใช้ Garudust? comment ได้เลยครับ 🙌&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>ai</category>
      <category>devops</category>
      <category>log</category>
    </item>
    <item>
      <title>Build a Self-Improving AI Agent in Rust with Garudust — Daily Briefing Bot in 10 Minutes</title>
      <dc:creator>Garudust</dc:creator>
      <pubDate>Sun, 17 May 2026 06:55:29 +0000</pubDate>
      <link>https://forem.com/garudust/build-a-self-improving-ai-agent-in-rust-with-garudust-daily-briefing-bot-in-10-minutes-ona</link>
      <guid>https://forem.com/garudust/build-a-self-improving-ai-agent-in-rust-with-garudust-daily-briefing-bot-in-10-minutes-ona</guid>
      <description>&lt;p&gt;Most AI agent frameworks feel like they were designed for Python developers who love ceremony. You write adapters, glue code, orchestrators, memory stores — and by the time your agent actually does something useful, you've got a monorepo and a headache.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/garudust-org/garudust-agent" rel="noopener noreferrer"&gt;Garudust Agent&lt;/a&gt;&lt;/strong&gt; takes a different approach: a single ~10 MB statically-linked Rust binary that gives you persistent memory, cron scheduling, multi-platform gateways (Telegram, Discord, Slack, Matrix), and MCP tool support — out of the box, no runtime dependencies.&lt;/p&gt;

&lt;p&gt;In this article I'll show you how to build a &lt;strong&gt;Telegram Daily Briefing Bot&lt;/strong&gt; that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wakes up every morning at 9 AM and sends you a personalised briefing&lt;/li&gt;
&lt;li&gt;Remembers your preferences across sessions (no repeating yourself)&lt;/li&gt;
&lt;li&gt;Reads files from your server and summarises them&lt;/li&gt;
&lt;li&gt;Uses a custom &lt;strong&gt;Skill&lt;/strong&gt; to keep its briefing format consistent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By the end you'll understand the core Garudust concepts well enough to build your own agents.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Garudust?
&lt;/h2&gt;

&lt;p&gt;Before diving in, here's what sets it apart from other agent runtimes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Garudust&lt;/th&gt;
&lt;th&gt;LangChain/LangGraph&lt;/th&gt;
&lt;th&gt;AutoGen&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Language&lt;/td&gt;
&lt;td&gt;Rust&lt;/td&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Binary size&lt;/td&gt;
&lt;td&gt;~10 MB&lt;/td&gt;
&lt;td&gt;N/A (pip install)&lt;/td&gt;
&lt;td&gt;N/A (pip install)&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;1–5 s&lt;/td&gt;
&lt;td&gt;1–5 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Persistent memory&lt;/td&gt;
&lt;td&gt;Built-in&lt;/td&gt;
&lt;td&gt;Plugin needed&lt;/td&gt;
&lt;td&gt;Plugin needed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Platform adapters&lt;/td&gt;
&lt;td&gt;Built-in&lt;/td&gt;
&lt;td&gt;Plugin needed&lt;/td&gt;
&lt;td&gt;Plugin needed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Self-hosted&lt;/td&gt;
&lt;td&gt;Yes, trivially&lt;/td&gt;
&lt;td&gt;Needs extra infra&lt;/td&gt;
&lt;td&gt;Needs extra infra&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The self-improvement angle is genuinely interesting: the agent notices when it keeps doing something wrong and patches its own Skill files. We'll see that in action below.&lt;/p&gt;




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

&lt;ul&gt;
&lt;li&gt;A Linux server or Mac (the binary is statically linked — no Rust required to run it)&lt;/li&gt;
&lt;li&gt;An API key for any LLM provider: Anthropic, OpenRouter, Ollama, vLLM, etc.&lt;/li&gt;
&lt;li&gt;A Telegram bot token (free — create one via &lt;a href="https://t.me/botfather" rel="noopener noreferrer"&gt;@BotFather&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;Download the 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;.&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;# Linux x86_64&lt;/span&gt;
curl &lt;span class="nt"&gt;-LO&lt;/span&gt; https://github.com/garudust-org/garudust-agent/releases/latest/download/garudust-x86_64-unknown-linux-musl.tar.gz
&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;.tar.gz
&lt;span class="nb"&gt;sudo mv &lt;/span&gt;garudust garudust-server /usr/local/bin/

&lt;span class="c"&gt;# Verify&lt;/span&gt;
garudust &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For macOS (Apple Silicon):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-LO&lt;/span&gt; https://github.com/garudust-org/garudust-agent/releases/latest/download/garudust-aarch64-apple-darwin.tar.gz
&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;.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 build from source if you have 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;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/target/release"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






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

&lt;p&gt;Run the 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 walks you through picking a provider and saving your key. Under the hood it writes to &lt;code&gt;~/.garudust/config.yaml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can also set environment variables directly:&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;# Anthropic&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ANTHROPIC_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"sk-ant-..."&lt;/span&gt;

&lt;span class="c"&gt;# OpenRouter (gives you access to 200+ models)&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OPENROUTER_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"sk-or-..."&lt;/span&gt;

&lt;span class="c"&gt;# Self-hosted vLLM (like the Qwen3-8B-AWQ setup I run locally)&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;VLLM_BASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:8000/v1"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GARUDUST_MODEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Qwen/Qwen3-8B-AWQ"&lt;/span&gt;

&lt;span class="c"&gt;# Ollama (fully local, no key needed)&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OLLAMA_BASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:11434"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GARUDUST_MODEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"llama3.2"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's verify everything is working:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;You should see all green checkmarks. Now try a quick chat:&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;"hello, what can you do?"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 3 — Create a Telegram Bot
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Open Telegram and message &lt;a href="https://t.me/botfather" rel="noopener noreferrer"&gt;@BotFather&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Send &lt;code&gt;/newbot&lt;/code&gt; and follow the prompts&lt;/li&gt;
&lt;li&gt;Copy your bot token (looks like &lt;code&gt;7123456789:AAHxxx...&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Set it in your environment:&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;export &lt;/span&gt;&lt;span class="nv"&gt;TELEGRAM_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"7123456789:AAHxxx..."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 4 — Create a Briefing Skill
&lt;/h2&gt;

&lt;p&gt;This is where Garudust gets interesting. &lt;strong&gt;Skills&lt;/strong&gt; are Markdown files that the agent automatically loads when relevant. They live in &lt;code&gt;~/.garudust/skills/&lt;/code&gt; and are hot-reloaded on every call — no restarts needed.&lt;/p&gt;

&lt;p&gt;Create the directory and your first skill:&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;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/.garudust/skills/daily-briefing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now create &lt;code&gt;~/.garudust/skills/daily-briefing/SKILL.md&lt;/code&gt;:&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;daily-briefing&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;Instructions for generating a personalised morning briefing via Telegram&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="nn"&gt;---&lt;/span&gt;

&lt;span class="gu"&gt;## Daily Briefing Format&lt;/span&gt;

When asked to generate a morning briefing, always follow this structure:
&lt;span class="p"&gt;
1.&lt;/span&gt; &lt;span class="gs"&gt;**Greeting**&lt;/span&gt; — Use the user's name and current local time
&lt;span class="p"&gt;2.&lt;/span&gt; &lt;span class="gs"&gt;**Today's Focus**&lt;/span&gt; — 2–3 bullet points on what to prioritise (infer from memory or files)
&lt;span class="p"&gt;3.&lt;/span&gt; &lt;span class="gs"&gt;**Quick Stats**&lt;/span&gt; — If any log files or data files are available in ~/briefing-data/, summarise key numbers
&lt;span class="p"&gt;4.&lt;/span&gt; &lt;span class="gs"&gt;**Reminder**&lt;/span&gt; — One motivational sentence, varied each day, never generic

&lt;span class="gu"&gt;## Style Rules&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Keep the total message under 300 words
&lt;span class="p"&gt;-&lt;/span&gt; Use Telegram-compatible formatting (bold with &lt;span class="err"&gt;*&lt;/span&gt;, italic with _)
&lt;span class="p"&gt;-&lt;/span&gt; Never use HTML tags
&lt;span class="p"&gt;-&lt;/span&gt; If no data files are found, skip the Quick Stats section gracefully
&lt;span class="p"&gt;-&lt;/span&gt; Always end with: "Have a great day, Garudian! 🦅"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That last line — "Have a great day, Garudian!" — is a nod to the Garudust contributor community name.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 5 — Set Up Cron Scheduling
&lt;/h2&gt;

&lt;p&gt;Garudust's cron scheduler uses standard cron expressions. You configure it via the &lt;code&gt;GARUDUST_CRON_JOBS&lt;/code&gt; environment variable:&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;export &lt;/span&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 * * *=Generate a morning briefing using the daily-briefing skill and send it to me on Telegram"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The format is &lt;code&gt;"cron_expression=natural language task"&lt;/code&gt;. The agent handles the rest — it knows who "me" is from the user profile it builds over time.&lt;/p&gt;

&lt;p&gt;You can also add multiple jobs separated by commas:&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;export &lt;/span&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 * * *=Generate a morning briefing and send via Telegram,0 18 * * 5=Send a weekly summary of tasks completed this week"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 6 — Start the Server
&lt;/h2&gt;

&lt;p&gt;Create a simple &lt;code&gt;.env&lt;/code&gt; file to keep everything together:&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;# ~/.garudust/.env&lt;/span&gt;
&lt;span class="nv"&gt;ANTHROPIC_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sk-ant-...
&lt;span class="nv"&gt;TELEGRAM_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;7123456789:AAHxxx...
&lt;span class="nv"&gt;GARUDUST_MODEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;anthropic/claude-sonnet-4-6
&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 * * *=Generate a morning briefing using the daily-briefing skill and send it to me on Telegram"&lt;/span&gt;
&lt;span class="nv"&gt;GARUDUST_APPROVAL_MODE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;auto
&lt;span class="nv"&gt;RUST_LOG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;info
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now start the server:&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;# Load env and start&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;source&lt;/span&gt; ~/.garudust/.env&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt; +a
garudust-server &lt;span class="nt"&gt;--port&lt;/span&gt; 3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or with Docker (the &lt;code&gt;docker-compose.yml&lt;/code&gt; in the repo is ready to use):&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;cp&lt;/span&gt; .env.example .env
&lt;span class="c"&gt;# Edit .env with your keys&lt;/span&gt;
docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see logs like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;INFO garudust_server: Starting Garudust server on port 3000
INFO garudust_platforms::telegram: Telegram adapter connected
INFO garudust_cron: Scheduled job: "0 9 * * *" → Generate a morning briefing...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 7 — Teach the Agent About You
&lt;/h2&gt;

&lt;p&gt;Open Telegram and message your bot. The first time, introduce yourself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Hi! I'm Alex. I'm a backend developer working on Rust microservices.
I usually check logs in ~/briefing-data/app.log and ~/briefing-data/errors.log.
I prefer short, direct messages with no fluff.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent saves this to persistent memory automatically. You'll see something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Got it, Alex! I've saved your preferences:
- Name: Alex
- Role: Backend developer (Rust microservices)
- Briefing data path: ~/briefing-data/
- Communication style: short and direct

I'll use these tomorrow morning at 9 AM for your briefing.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the self-improvement loop: you teach it once, and it remembers forever. On the next session — or the next day's cron job — the context is already loaded.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Happens at 9 AM
&lt;/h2&gt;

&lt;p&gt;At 9 AM, the cron job fires. The agent:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Loads the daily-briefing Skill&lt;/strong&gt; — sees the format rules&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reads persistent memory&lt;/strong&gt; — knows your name, preferences, file paths&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Calls &lt;code&gt;read_file&lt;/code&gt;&lt;/strong&gt; on &lt;code&gt;~/briefing-data/app.log&lt;/code&gt; and &lt;code&gt;errors.log&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generates the briefing&lt;/strong&gt; using the Skill's format&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sends it to you on Telegram&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A real message might look like:&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="ge"&gt;*Good morning, Alex!*&lt;/span&gt; It's 9:00 AM.

&lt;span class="ge"&gt;*Today's Focus*&lt;/span&gt;
• 3 errors in errors.log since yesterday — worth a look before standup
• PR #142 still open — you had this on your radar
• Dependency audit due this sprint

&lt;span class="ge"&gt;*Quick Stats (from app.log)*&lt;/span&gt;
• 14,203 requests last 24h
• p99 latency: 187 ms
• 3 ERRORs, 0 WARNings

&lt;span class="ge"&gt;_Have a great day, Garudian!_&lt;/span&gt; 🦅
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 8 — Test the HTTP API
&lt;/h2&gt;

&lt;p&gt;You don't have to wait until 9 AM. The HTTP gateway is always running:&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;# Trigger a briefing right now&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": "Generate my morning briefing now and send it to me on Telegram"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For streaming responses (great for long tasks):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&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": "Summarise my error logs from the last 7 days"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 9 — Run as a systemd Service
&lt;/h2&gt;

&lt;p&gt;For production use on a Linux server:&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;sudo &lt;/span&gt;nano /etc/systemd/system/garudust.service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[Unit]&lt;/span&gt;
&lt;span class="py"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;Garudust Agent Server&lt;/span&gt;
&lt;span class="py"&gt;After&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;network.target&lt;/span&gt;

&lt;span class="nn"&gt;[Service]&lt;/span&gt;
&lt;span class="py"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;simple&lt;/span&gt;
&lt;span class="py"&gt;User&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;youruser&lt;/span&gt;
&lt;span class="py"&gt;WorkingDirectory&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/home/youruser&lt;/span&gt;
&lt;span class="py"&gt;EnvironmentFile&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/home/youruser/.garudust/.env&lt;/span&gt;
&lt;span class="py"&gt;ExecStart&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/usr/local/bin/garudust-server --port 3000&lt;/span&gt;
&lt;span class="py"&gt;Restart&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;on-failure&lt;/span&gt;
&lt;span class="py"&gt;RestartSec&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;5s&lt;/span&gt;

&lt;span class="nn"&gt;[Install]&lt;/span&gt;
&lt;span class="py"&gt;WantedBy&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;multi-user.target&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl daemon-reload
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;--now&lt;/span&gt; garudust
&lt;span class="nb"&gt;sudo &lt;/span&gt;journalctl &lt;span class="nt"&gt;-u&lt;/span&gt; garudust &lt;span class="nt"&gt;-f&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Self-Improving Part
&lt;/h2&gt;

&lt;p&gt;Here's something that makes Garudust distinct from a static chatbot: if the briefing format stops being useful, the agent fixes itself.&lt;/p&gt;

&lt;p&gt;Suppose you message your bot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The briefing is too long. Cut the Quick Stats section to just one line.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent updates &lt;code&gt;~/.garudust/skills/daily-briefing/SKILL.md&lt;/code&gt; immediately — while the server is running, without a restart. The next morning's briefing will already follow the updated format.&lt;/p&gt;

&lt;p&gt;You can also ask it to create new skills on the fly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="n"&gt;Write&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;skill&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;when&lt;/span&gt; &lt;span class="n"&gt;I&lt;/span&gt; &lt;span class="n"&gt;ask&lt;/span&gt; &lt;span class="n"&gt;you&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;review&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;Rust&lt;/span&gt; &lt;span class="n"&gt;PR&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;unwraps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;missing&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="n"&gt;handling&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;and&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="n"&gt;comments&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It creates &lt;code&gt;~/.garudust/skills/rust-pr-review/SKILL.md&lt;/code&gt; automatically. From that point on, whenever you paste a PR and ask for a review, it loads that skill without being told.&lt;/p&gt;




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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Your Telegram ──► garudust-server
                       │
                  ┌────┴────────────────────┐
                  │   daily-briefing SKILL  │  ← hot-reloaded markdown
                  │   Persistent Memory     │  ← ~/.garudust/memory/
                  │   Session DB (FTS5)     │  ← SQLite full-text search
                  └────┬────────────────────┘
                       │
                  LLM Transport
          (Anthropic / OpenRouter / vLLM / Ollama)
                       │
                  Tool Registry
         (read_file, write_skill, memory, web_search…)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every piece is a separate Rust crate. If you want to add a new platform or tool, you touch exactly one crate and typically write under 100 lines.&lt;/p&gt;




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

&lt;p&gt;Now that you have the basics, here are some natural extensions:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Add web search to the briefing&lt;/strong&gt;&lt;br&gt;
Set &lt;code&gt;BRAVE_SEARCH_API_KEY&lt;/code&gt; and update your Skill to include: "Always search for the top 3 tech news headlines and include them under a 'News' section."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multi-platform&lt;/strong&gt;: Run Telegram + Slack simultaneously&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;export &lt;/span&gt;&lt;span class="nv"&gt;SLACK_BOT_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"xoxb-..."&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SLACK_APP_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"xapp-..."&lt;/span&gt;
&lt;span class="c"&gt;# garudust-server handles both in the same process&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Connect to your database via MCP&lt;/strong&gt;&lt;br&gt;
Add to &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;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;p&gt;The briefing can now query your own database directly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Delegate to sub-agents&lt;/strong&gt;&lt;br&gt;
For heavy tasks, use the &lt;code&gt;delegate_task&lt;/code&gt; tool — it spawns parallel sub-agents that run concurrently and report back. Great for summarising large codebases or doing multi-step research.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Garudust isn't trying to be the most featureful agent framework — it's trying to be the most &lt;strong&gt;practical&lt;/strong&gt; one. A single binary, sensible defaults, and just enough structure to let you build real things without ceremony.&lt;/p&gt;

&lt;p&gt;The daily briefing bot we built today shows the core loop:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Install&lt;/strong&gt; — one binary, no dependencies&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configure&lt;/strong&gt; — env vars or YAML&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Teach&lt;/strong&gt; — talk to it, it remembers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extend&lt;/strong&gt; — write a Skill in Markdown&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The project is actively developed and welcoming contributors. If you want to add a new platform adapter, a tool, or improve the TUI — check out the &lt;a href="https://github.com/garudust-org/garudust-agent/blob/main/CONTRIBUTING.md" rel="noopener noreferrer"&gt;CONTRIBUTING.md&lt;/a&gt; and look for "good first issue" labels.&lt;/p&gt;

&lt;p&gt;Star the repo, join the community, and become a &lt;strong&gt;Garudian&lt;/strong&gt; 🦅&lt;/p&gt;

&lt;p&gt;→ &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;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Have questions or want to share what you built? Drop a comment below — I read everything.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>ai</category>
      <category>llm</category>
      <category>telegram</category>
    </item>
    <item>
      <title>สร้าง AI Agent บน LINE ด้วย Garudust (Rust) — ตั้งแต่ต้นจนใช้งานได้จริง</title>
      <dc:creator>Garudust</dc:creator>
      <pubDate>Thu, 14 May 2026 05:06:47 +0000</pubDate>
      <link>https://forem.com/garudust/sraang-ai-agent-bn-line-dwy-garudust-rust-tangaettncchnaichngaanaidcchring-4pgj</link>
      <guid>https://forem.com/garudust/sraang-ai-agent-bn-line-dwy-garudust-rust-tangaettncchnaichngaanaidcchring-4pgj</guid>
      <description>&lt;p&gt;ถ้าคุณอยากมี AI Agent ส่วนตัวที่คุยได้ผ่าน LINE โดยไม่ต้องพึ่ง no-code platform บทความนี้จะพาคุณทำตั้งแต่ต้นจนจบ เครื่องมือที่ใช้คือ &lt;strong&gt;&lt;a href="https://github.com/garudust-org/garudust-agent" rel="noopener noreferrer"&gt;Garudust&lt;/a&gt;&lt;/strong&gt; — AI Agent framework เขียนด้วย Rust รองรับ OpenAI, Anthropic, Ollama, vLLM และ OpenAI-compatible endpoint ทุกเจ้า&lt;/p&gt;




&lt;h2&gt;
  
  
  สิ่งที่ต้องมี
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;เซิร์ฟเวอร์ Linux หรือ macOS (หรือรันบน VPS ก็ได้)&lt;/li&gt;
&lt;li&gt;บัญชี LINE Developers (ฟรี) → &lt;a href="https://developers.line.biz" rel="noopener noreferrer"&gt;developers.line.biz&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;API Key จาก OpenAI, Anthropic, หรือ endpoint อื่นๆ&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ngrok.com" rel="noopener noreferrer"&gt;ngrok&lt;/a&gt; — &lt;strong&gt;เฉพาะกรณีรันบนเครื่องตัวเองที่ไม่มี public IP&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  1. ติดตั้ง Garudust
&lt;/h2&gt;

&lt;h3&gt;
  
  
  วิธีที่ 1 — ดาวน์โหลด binary
&lt;/h3&gt;

&lt;p&gt;ไปที่ &lt;a href="https://github.com/garudust-org/garudust-agent/releases" rel="noopener noreferrer"&gt;Releases&lt;/a&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;# Linux x86_64&lt;/span&gt;
curl &lt;span class="nt"&gt;-LO&lt;/span&gt; https://github.com/garudust-org/garudust-agent/releases/latest/download/garudust-v0.3.1-x86_64-unknown-linux-musl.tar.gz
&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;.tar.gz
&lt;span class="nb"&gt;sudo mv &lt;/span&gt;garudust&lt;span class="k"&gt;*&lt;/span&gt;/garudust garudust&lt;span class="k"&gt;*&lt;/span&gt;/garudust-server /usr/local/bin/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  วิธีที่ 2 — Build จาก source (ต้องมี Rust 1.87+)
&lt;/h3&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.git
&lt;span class="nb"&gt;cd &lt;/span&gt;garudust-agent
cargo build &lt;span class="nt"&gt;--release&lt;/span&gt; &lt;span class="nt"&gt;--bin&lt;/span&gt; garudust &lt;span class="nt"&gt;--bin&lt;/span&gt; garudust-server
&lt;span class="nb"&gt;sudo cp &lt;/span&gt;target/release/garudust target/release/garudust-server /usr/local/bin/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ตรวจสอบว่าติดตั้งสำเร็จ:&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="nt"&gt;--version&lt;/span&gt;
garudust-server &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  2. ตั้งค่า LINE Messaging API
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;เข้าไปที่ &lt;a href="https://developers.line.biz" rel="noopener noreferrer"&gt;LINE Developers Console&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;สร้าง &lt;strong&gt;Provider&lt;/strong&gt; ใหม่ (หรือใช้อันที่มีอยู่)&lt;/li&gt;
&lt;li&gt;สร้าง &lt;strong&gt;Channel&lt;/strong&gt; ประเภท &lt;strong&gt;Messaging API&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;ที่ tab &lt;strong&gt;Basic settings&lt;/strong&gt; → คัดลอก &lt;strong&gt;Channel secret&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;ที่ tab &lt;strong&gt;Messaging API&lt;/strong&gt; → คลิก &lt;strong&gt;Issue&lt;/strong&gt; เพื่อสร้าง &lt;strong&gt;Channel access token&lt;/strong&gt; (long-lived)&lt;/li&gt;
&lt;li&gt;เปิด &lt;strong&gt;Use webhook&lt;/strong&gt; → toggle เป็น Enable&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;เก็บค่าสองอย่างนี้ไว้:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;LINE_CHANNEL_SECRET&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&lt;/span&gt;
&lt;span class="py"&gt;LINE_CHANNEL_TOKEN&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;eyJhbGci...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. ตั้งค่าไฟล์ config
&lt;/h2&gt;

&lt;p&gt;Garudust แยก secret ออกจาก config เป็น 2 ไฟล์:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;~/.garudust/.env&lt;/code&gt; — credentials เท่านั้น (ห้าม commit)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;~/.garudust/config.yaml&lt;/code&gt; — ตั้งค่าพฤติกรรม, platform, port (แชร์ได้)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;~/.garudust/.env&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# LLM provider&lt;/span&gt;
&lt;span class="nv"&gt;ANTHROPIC_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sk-ant-...

&lt;span class="c"&gt;# LINE adapter — tokens ต้องอยู่ใน .env เสมอ&lt;/span&gt;
&lt;span class="nv"&gt;LINE_CHANNEL_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
&lt;span class="nv"&gt;LINE_CHANNEL_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;eyJhbGci...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;~/.garudust/config.yaml&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;anthropic&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;claude-sonnet-4-6&lt;/span&gt;

&lt;span class="na"&gt;system_prompt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
  &lt;span class="s"&gt;คุณคือผู้ช่วย AI ชื่อ "น้องการุด" พูดภาษาไทย ตอบสั้นกระชับ&lt;/span&gt;
  &lt;span class="s"&gt;ช่วยงานด้านข้อมูล วิเคราะห์ข้อความ และตอบคำถามทั่วไป&lt;/span&gt;
  &lt;span class="s"&gt;ไม่ตอบเนื้อหาที่ไม่เหมาะสม&lt;/span&gt;

&lt;span class="na"&gt;platforms&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;line&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;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3002&lt;/span&gt;
    &lt;span class="na"&gt;webhook_path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/line&lt;/span&gt;      &lt;span class="c1"&gt;# webhook URL: https://your-host/line&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;หลักการ:&lt;/strong&gt; &lt;code&gt;config.yaml&lt;/code&gt; เก็บโครงสร้าง (&lt;code&gt;enabled&lt;/code&gt;, &lt;code&gt;port&lt;/code&gt;, &lt;code&gt;webhook_path&lt;/code&gt;) ส่วน &lt;code&gt;.env&lt;/code&gt; เก็บ secret (&lt;code&gt;LINE_CHANNEL_SECRET&lt;/code&gt;, &lt;code&gt;LINE_CHANNEL_TOKEN&lt;/code&gt;) เท่านั้น&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;เมื่อรัน &lt;code&gt;garudust-server&lt;/code&gt; แล้ว Garudust จะเปิด HTTP server รอรับ webhook จาก LINE ที่ &lt;code&gt;0.0.0.0:3002/line&lt;/code&gt; โดยอัตโนมัติ — &lt;strong&gt;ไม่ต้องตั้งค่า webhook server เพิ่มเอง&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  4. รัน garudust-server
&lt;/h2&gt;



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

&lt;/div&gt;



&lt;p&gt;ดู log จะเห็น:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;INFO garudust_server: LINE webhook listening on 0.0.0.0:3002/line
INFO garudust_server: API server listening on 0.0.0.0:3000
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Port mapping ของ Garudust:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Port&lt;/th&gt;
&lt;th&gt;ใช้สำหรับ&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;3000&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;HTTP API หลัก (&lt;code&gt;/chat&lt;/code&gt;, &lt;code&gt;/health&lt;/code&gt;, &lt;code&gt;/metrics&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;3001&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Generic webhook&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;3002&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;LINE adapter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;3003&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;WhatsApp adapter&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  5. ตั้งค่า Webhook URL ใน LINE Developers Console
&lt;/h2&gt;

&lt;p&gt;ขั้นตอนนี้แตกต่างกันตามสภาพแวดล้อม:&lt;/p&gt;

&lt;h3&gt;
  
  
  กรณี A — VPS หรือเซิร์ฟเวอร์ที่มี public IP (Production)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;ไม่ต้องใช้ ngrok&lt;/strong&gt; — LINE เข้าถึง server ของคุณได้ตรงๆ ผ่าน nginx&lt;/p&gt;

&lt;p&gt;ตั้งค่า nginx reverse proxy ก่อน (ดูขั้นตอนที่ 7) แล้วใช้ URL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://yourdomain.com/line
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  กรณี B — เครื่องตัวเองที่ไม่มี public IP (Dev/ทดสอบ)
&lt;/h3&gt;

&lt;p&gt;LINE ไม่สามารถเข้าถึง &lt;code&gt;localhost&lt;/code&gt; ได้และต้องการ HTTPS — ใช้ ngrok สร้าง tunnel ชั่วคราว:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ngrok http 3002
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ngrok จะแสดง URL เช่น:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;Forwarding  https://abc123.ngrok-free.app -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;http://localhost:3002
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;webhook URL ของคุณคือ:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://abc123.ngrok-free.app/line
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;หมายเหตุ:&lt;/strong&gt; ngrok free tier เปลี่ยน URL ทุกครั้งที่รีสตาร์ท เหมาะสำหรับทดสอบเท่านั้น ใช้ VPS หรือ ngrok paid plan สำหรับ production&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;ตั้ง webhook URL ใน LINE Developers Console:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Tab &lt;strong&gt;Messaging API&lt;/strong&gt; → ส่วน &lt;strong&gt;Webhook settings&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;ใส่ URL ตามสภาพแวดล้อมของคุณ (จากด้านบน)&lt;/li&gt;
&lt;li&gt;คลิก &lt;strong&gt;Verify&lt;/strong&gt; — ควรได้ "Success"&lt;/li&gt;
&lt;li&gt;เปิด &lt;strong&gt;Use webhook&lt;/strong&gt; ให้เป็น Enable&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ลองส่งข้อความหา LINE Official Account ของคุณ — AI จะตอบกลับทันที&lt;/p&gt;




&lt;h2&gt;
  
  
  6. เพิ่ม Cron Job (ทำงานอัตโนมัติ)
&lt;/h2&gt;

&lt;p&gt;Garudust มีระบบ cron ในตัว ตั้งค่าใน &lt;code&gt;.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;# ส่ง briefing ทุกเช้า 8 โมง&lt;/span&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 8 * * *=สรุปข่าวเทคโนโลยีไทยวันนี้ บันทึกลงไฟล์ ~/briefing.md"&lt;/span&gt;

&lt;span class="c"&gt;# รวบรวม memory อัตโนมัติทุกคืน 03:00&lt;/span&gt;
&lt;span class="nv"&gt;GARUDUST_MEMORY_CRON&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"0 3 * * *"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  7. Deploy Production (systemd + nginx)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  nginx reverse proxy
&lt;/h3&gt;

&lt;p&gt;LINE ต้องการ HTTPS — nginx จัดการ SSL แล้ว proxy ต่อไปยัง Garudust บน port 3002:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="c1"&gt;# /etc/nginx/sites-available/garudust&lt;/span&gt;
&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;443&lt;/span&gt; &lt;span class="s"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;yourdomain.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;ssl_certificate&lt;/span&gt;     &lt;span class="n"&gt;/etc/letsencrypt/live/yourdomain.com/fullchain.pem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;ssl_certificate_key&lt;/span&gt; &lt;span class="n"&gt;/etc/letsencrypt/live/yourdomain.com/privkey.pem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;# LINE webhook — proxy ไปที่ Garudust LINE adapter port 3002&lt;/span&gt;
    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/line&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://127.0.0.1:3002&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Host&lt;/span&gt; &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Real-IP&lt;/span&gt; &lt;span class="nv"&gt;$remote_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;# HTTP API หลัก&lt;/span&gt;
    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://127.0.0.1:3000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Host&lt;/span&gt; &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; /etc/nginx/sites-available/garudust /etc/nginx/sites-enabled/
&lt;span class="nb"&gt;sudo &lt;/span&gt;nginx &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl reload nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  systemd service
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="c"&gt;# /etc/systemd/system/garudust.service
&lt;/span&gt;&lt;span class="nn"&gt;[Unit]&lt;/span&gt;
&lt;span class="py"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;Garudust AI Agent Server&lt;/span&gt;
&lt;span class="py"&gt;After&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;network.target&lt;/span&gt;

&lt;span class="nn"&gt;[Service]&lt;/span&gt;
&lt;span class="py"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;simple&lt;/span&gt;
&lt;span class="py"&gt;User&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;ubuntu&lt;/span&gt;
&lt;span class="py"&gt;ExecStart&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/usr/local/bin/garudust-server&lt;/span&gt;
&lt;span class="py"&gt;Restart&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;on-failure&lt;/span&gt;
&lt;span class="py"&gt;RestartSec&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;5&lt;/span&gt;
&lt;span class="py"&gt;EnvironmentFile&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/home/ubuntu/.garudust/.env&lt;/span&gt;
&lt;span class="py"&gt;WorkingDirectory&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/home/ubuntu&lt;/span&gt;

&lt;span class="nn"&gt;[Install]&lt;/span&gt;
&lt;span class="py"&gt;WantedBy&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;multi-user.target&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl daemon-reload
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;--now&lt;/span&gt; garudust
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl status garudust
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;webhook URL สำหรับตั้งใน LINE Console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://yourdomain.com/line
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  สรุป config ทั้งหมด
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;~/.garudust/.env&lt;/code&gt;&lt;/strong&gt; — secrets เท่านั้น&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;ANTHROPIC_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sk-ant-...
&lt;span class="nv"&gt;LINE_CHANNEL_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
&lt;span class="nv"&gt;LINE_CHANNEL_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;eyJhbGci...
&lt;span class="nv"&gt;GARUDUST_MEMORY_CRON&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"0 3 * * *"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;~/.garudust/config.yaml&lt;/code&gt;&lt;/strong&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;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;anthropic&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;claude-sonnet-4-6&lt;/span&gt;

&lt;span class="na"&gt;system_prompt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
  &lt;span class="s"&gt;คุณคือผู้ช่วย AI ชื่อ "น้องการุด" พูดภาษาไทย ตอบสั้นกระชับ&lt;/span&gt;

&lt;span class="na"&gt;platforms&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;line&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;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3002&lt;/span&gt;
    &lt;span class="na"&gt;webhook_path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/line&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  สรุปขั้นตอนตามสภาพแวดล้อม
&lt;/h2&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;Dev (localhost)&lt;/th&gt;
&lt;th&gt;Production (VPS)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Garudust รัน webhook ที่&lt;/td&gt;
&lt;td&gt;&lt;code&gt;localhost:3002/line&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;localhost:3002/line&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;เปิด HTTPS ด้วย&lt;/td&gt;
&lt;td&gt;ngrok tunnel&lt;/td&gt;
&lt;td&gt;nginx + Let's Encrypt&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Webhook URL ใน LINE Console&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://xxx.ngrok-free.app/line&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://yourdomain.com/line&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ngrok&lt;/td&gt;
&lt;td&gt;✅ จำเป็น&lt;/td&gt;
&lt;td&gt;❌ ไม่ต้อง&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Garudust รองรับ OpenAI, Anthropic, Ollama, vLLM และ OpenAI-compatible endpoint ทุกเจ้า — เปลี่ยน provider ได้แค่แก้ 2 บรรทัดใน &lt;code&gt;config.yaml&lt;/code&gt; แล้วรีสตาร์ท&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/garudust-org/garudust-agent" rel="noopener noreferrer"&gt;garudust-org/garudust-agent&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docs:&lt;/strong&gt; &lt;a href="https://garudust-org.github.io/garudust-agent" rel="noopener noreferrer"&gt;garudust-org.github.io/garudust-agent&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ถ้ามีคำถามหรือเจอปัญหา เปิด Issue บน GitHub ได้เลย หรือ comment ไว้ด้านล่างครับ&lt;/p&gt;

</description>
      <category>rust</category>
      <category>ai</category>
      <category>line</category>
      <category>chatbot</category>
    </item>
    <item>
      <title>ใช้งาน Garudust Agent ร่วมกับ Typhoon Thai LLM: คู่มือฉบับสมบูรณ์</title>
      <dc:creator>Garudust</dc:creator>
      <pubDate>Wed, 13 May 2026 14:07:29 +0000</pubDate>
      <link>https://forem.com/garudust/aichngaan-garudust-agent-rwmkab-typhoon-thai-llm-khuumuuechbabsmbuurn-3b6c</link>
      <guid>https://forem.com/garudust/aichngaan-garudust-agent-rwmkab-typhoon-thai-llm-khuumuuechbabsmbuurn-3b6c</guid>
      <description>&lt;p&gt;Garudust เป็น AI agent ที่เขียนด้วย Rust — binary ขนาด ~10 MB, cold start ไม่ถึง 20 มิลลิวินาที และมี persistent memory ที่จำทุกอย่างข้ามหลาย session&lt;/p&gt;

&lt;p&gt;แต่ถ้างานที่ทำเป็นภาษาไทยล้วนๆ — เขียนอีเมลธุรกิจ, ตอบลูกค้า LINE OA, สรุปเอกสารราชการ — การใช้ &lt;strong&gt;Typhoon&lt;/strong&gt; โมเดลภาษาไทยจาก SCB 10X จะได้ผลลัพธ์ที่ดีกว่าอย่างชัดเจน&lt;/p&gt;

&lt;p&gt;Typhoon มี &lt;strong&gt;free API ที่ compatible กับ OpenAI&lt;/strong&gt; ที่ &lt;code&gt;https://api.opentyphoon.ai/v1&lt;/code&gt; ซึ่งหมายความว่า Garudust เชื่อมต่อได้ทันทีด้วยการตั้งค่า 2 บรรทัด ไม่ต้องแก้โค้ดแม้แต่บรรทัดเดียว&lt;/p&gt;




&lt;h2&gt;
  
  
  สิ่งที่ต้องเตรียม
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Linux, macOS หรือ Windows (WSL2)&lt;/li&gt;
&lt;li&gt;Rust 1.75+ — หรือดาวน์โหลด pre-built binary เลยก็ได้&lt;/li&gt;
&lt;li&gt;API key จาก &lt;a href="https://opentyphoon.ai" rel="noopener noreferrer"&gt;opentyphoon.ai&lt;/a&gt; (ฟรี)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ขั้นตอนที่ 1 — ขอ Typhoon API Key
&lt;/h2&gt;

&lt;p&gt;ไปที่ &lt;a href="https://opentyphoon.ai" rel="noopener noreferrer"&gt;opentyphoon.ai&lt;/a&gt; สมัครบัญชีฟรี แล้ว generate API key จาก dashboard&lt;/p&gt;

&lt;p&gt;API key จะมีหน้าตาประมาณนี้:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sk-ty-xxxxxxxxxxxxxxxxxxxxxxxxxxxx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Free tier ใช้งานได้กับทั้ง 2 โมเดล:&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;Req/วินาที&lt;/th&gt;
&lt;th&gt;Req/นาที&lt;/th&gt;
&lt;th&gt;เหมาะกับ&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;typhoon-v2.1-12b-instruct&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;งานทั่วไป, ตอบเร็ว&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;typhoon-v2.5-30b-a3b-instruct&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;งานซับซ้อน, reasoning&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;สำหรับงาน agent ส่วนใหญ่ แนะนำ &lt;code&gt;typhoon-v2.1-12b-instruct&lt;/code&gt; ก่อน — เร็วกว่าและเหมาะกับ multi-turn loop มากกว่า&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;หมายเหตุ:&lt;/strong&gt; Free API มี rate limit และไม่เหมาะกับ production workload หนักๆ สำหรับการใช้งานจริงในระดับ enterprise รอ production API บน AWS ที่ Typhoon วางแผนจะเปิดในปี 2026&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  ขั้นตอนที่ 2 — ติดตั้ง Garudust
&lt;/h2&gt;

&lt;h3&gt;
  
  
  วิธีที่ 1: ดาวน์โหลด binary สำเร็จรูป (แนะนำ)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Linux x86_64&lt;/span&gt;
curl &lt;span class="nt"&gt;-LO&lt;/span&gt; https://github.com/garudust-org/garudust-agent/releases/latest/download/garudust-x86_64-unknown-linux-musl.tar.gz
&lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xzf&lt;/span&gt; garudust-x86_64-unknown-linux-musl.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;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;แพลตฟอร์ม&lt;/th&gt;
&lt;th&gt;ไฟล์&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Linux x86_64&lt;/td&gt;
&lt;td&gt;&lt;code&gt;garudust-*-x86_64-unknown-linux-musl.tar.gz&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linux ARM64&lt;/td&gt;
&lt;td&gt;&lt;code&gt;garudust-*-aarch64-unknown-linux-musl.tar.gz&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;macOS Apple Silicon&lt;/td&gt;
&lt;td&gt;&lt;code&gt;garudust-*-aarch64-apple-darwin.tar.gz&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;macOS Intel&lt;/td&gt;
&lt;td&gt;&lt;code&gt;garudust-*-x86_64-apple-darwin.tar.gz&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows&lt;/td&gt;
&lt;td&gt;&lt;code&gt;garudust-*-x86_64-pc-windows-msvc.zip&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  วิธีที่ 2: ติดตั้งจาก crates.io
&lt;/h3&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;ตรวจสอบว่าติดตั้งสำเร็จ:&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="nt"&gt;--version&lt;/span&gt;
&lt;span class="c"&gt;# garudust 0.2.8&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ขั้นตอนที่ 3 — เชื่อมต่อ Garudust กับ Typhoon
&lt;/h2&gt;

&lt;p&gt;Garudust แยก config ออกจาก secret เป็น 2 ไฟล์ใน &lt;code&gt;~/.garudust/&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;config.yaml&lt;/code&gt; — ชื่อโมเดล, provider, ค่าพฤติกรรมต่างๆ (แชร์ได้)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.env&lt;/code&gt; — API key อย่างเดียว (ห้าม commit เด็ดขาด)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;สร้างไฟล์ &lt;code&gt;~/.garudust/config.yaml&lt;/code&gt;:&lt;/strong&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;# เชื่อมต่อ Typhoon ผ่าน OpenAI-compatible endpoint&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="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;typhoon-v2.1-12b-instruct&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;https://api.opentyphoon.ai/v1&lt;/span&gt;

&lt;span class="c1"&gt;# Context window สำหรับโมเดล 12B&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;8192&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;span class="c1"&gt;# Memory nudge — บันทึก fact ทุก 5 iteration&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;สร้างไฟล์ &lt;code&gt;~/.garudust/.env&lt;/code&gt;:&lt;/strong&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;# Typhoon API key&lt;/span&gt;
&lt;span class="nv"&gt;VLLM_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sk-ty-xxxxxxxxxxxxxxxxxxxxxxxxxxxx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;ทำไมใช้ &lt;code&gt;VLLM_API_KEY&lt;/code&gt;?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Garudust ส่ง key นี้เป็น &lt;code&gt;Authorization: Bearer&lt;/code&gt; header ไปยัง base_url ที่กำหนด Typhoon API รับ format นี้ได้ตรงๆ เลย&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;หรือจะใช้ 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;เลือก provider เป็น &lt;strong&gt;vllm&lt;/strong&gt; แล้วกรอก &lt;code&gt;base_url&lt;/code&gt; และ &lt;code&gt;model&lt;/code&gt; ตามด้านบน&lt;/p&gt;




&lt;h2&gt;
  
  
  ขั้นตอนที่ 4 — ตรวจสอบการเชื่อมต่อ
&lt;/h2&gt;



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

&lt;/div&gt;



&lt;p&gt;ถ้าทุกอย่างถูกต้องจะเห็น:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;✓ Config loaded     provider=vllm  model=typhoon-v2.1-12b-instruct
✓ API key present   VLLM_API_KEY
✓ LLM reachable     https://api.opentyphoon.ai/v1 → 200 OK
✓ Memory dir        ~/.garudust/memory/ (0 entries)
✓ Session DB        ~/.garudust/sessions.db
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ขั้นตอนที่ 5 — ทดสอบสนทนาภาษาไทย
&lt;/h2&gt;

&lt;p&gt;เปิด TUI แบบ interactive:&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ลองพิมพ์:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;คุณ: สวัสดีครับ ช่วยแนะนำตัวเองหน่อยได้ไหม
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agent จะตรวจจับภาษาไทยโดยอัตโนมัติและตอบกลับเป็นภาษาไทย โดยไม่ต้องตั้งค่าภาษาเพิ่มเติม&lt;/p&gt;

&lt;p&gt;หรือใช้แบบ one-shot:&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;"สรุปข้อดีข้อเสียของการเปิดบริษัทในไทยแบบสั้นๆ"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ขั้นตอนที่ 6 — ตั้งให้ตอบไทยเป็นค่าเริ่มต้นถาวร
&lt;/h2&gt;

&lt;p&gt;บอก agent ครั้งเดียว มันจำตลอด:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;คุณ: ตั้งแต่นี้ไปตอบเป็นภาษาไทยเสมอ ยกเว้นถ้าฉันถามเป็นภาษาอื่น
Agent: [บันทึกลง memory] เข้าใจแล้วครับ จะตอบเป็นภาษาไทยใน session หน้าทุกครั้ง
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Garudust บันทึกลง &lt;code&gt;~/.garudust/memory/&lt;/code&gt; และโหลดขึ้นมาทุก session โดยอัตโนมัติ ไม่ต้องบอกซ้ำอีก&lt;/p&gt;




&lt;h2&gt;
  
  
  ตัวอย่างการใช้งานจริง
&lt;/h2&gt;

&lt;h3&gt;
  
  
  เขียนอีเมลธุรกิจภาษาไทย
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;garudust &lt;span class="s2"&gt;"เขียนอีเมลทางการถึงพาร์ทเนอร์ แจ้งว่าต้องการต่อสัญญา partnership อีก 1 ปี พร้อมเสนอเพิ่มงบ 15% และขอนัดประชุมสัปดาห์หน้า"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  สรุปเอกสาร PDF ภาษาไทย
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;garudust &lt;span class="s2"&gt;"อ่านไฟล์นี้แล้วสรุปประเด็นสำคัญเป็นภาษาไทย 5 ข้อ: /path/to/contract.pdf"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agent จะเรียก &lt;code&gt;pdf_read&lt;/code&gt; tool โดยอัตโนมัติ แล้วสรุปเนื้อหาให้&lt;/p&gt;

&lt;h3&gt;
  
  
  เขียน template ตอบ LINE OA
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;garudust &lt;span class="s2"&gt;"เขียน template ตอบลูกค้าใน LINE OA สำหรับคำถามเรื่อง shipping 5 แบบ ให้เป็นภาษาไทยที่สุภาพและเป็นมิตร พร้อมระบุวันจัดส่งโดยประมาณ"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  สร้าง skill ภาษาไทยให้ใช้ซ้ำได้
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;คุณ: สร้าง skill สำหรับเขียนรายงานสรุปประจำสัปดาห์เป็นภาษาไทย พร้อม format หัวข้อ ผลงานที่ทำ ปัญหาที่พบ และแผนสัปดาห์หน้า
Agent: [เรียก write_skill]
       บันทึก skill 'weekly-report-th' ไปยัง ~/.garudust/skills/weekly-report-th/SKILL.md แล้ว
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ครั้งต่อไปแค่พิมพ์:&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;"ใช้ skill weekly-report-th สรุปสัปดาห์นี้"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ส่ง briefing ภาษาไทยทุกเช้า (Cron)
&lt;/h3&gt;

&lt;p&gt;เพิ่มใน &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="nv"&gt;GARUDUST_CRON_JOBS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"0 8 * * *=ค้นหาข่าวเศรษฐกิจและเทคโนโลยีไทยล่าสุด สรุปเป็นรายการ 5 ข้อ บันทึกลงไฟล์ ~/briefing-th.md"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เปิด server:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;ทุกวันตี 8 โมงเช้า agent จะค้นหาข่าว สรุปเป็นภาษาไทย และบันทึกไฟล์ให้โดยอัตโนมัติ&lt;/p&gt;




&lt;h2&gt;
  
  
  เปลี่ยนเป็นโมเดลใหญ่เมื่อต้องการ
&lt;/h2&gt;

&lt;p&gt;สำหรับงานที่ซับซ้อนกว่า เช่น วิเคราะห์สัญญา หรือ multi-step planning:&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;# เปลี่ยนชั่วคราวใน TUI&lt;/span&gt;
/model typhoon-v2.5-30b-a3b-instruct

&lt;span class="c"&gt;# หรือเปลี่ยนถาวร&lt;/span&gt;
garudust config &lt;span class="nb"&gt;set &lt;/span&gt;model typhoon-v2.5-30b-a3b-instruct
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;อย่าลืมอัปเดต &lt;code&gt;context_window&lt;/code&gt; ใน &lt;code&gt;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;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;typhoon-v2.5-30b-a3b-instruct&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  แก้ปัญหาเบื้องต้น
&lt;/h2&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;สาเหตุ&lt;/th&gt;
&lt;th&gt;วิธีแก้&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;HTTP 401 Unauthorized&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;API key ผิด&lt;/td&gt;
&lt;td&gt;ตรวจสอบ &lt;code&gt;VLLM_API_KEY&lt;/code&gt; ใน &lt;code&gt;~/.garudust/.env&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;HTTP 429 Too Many Requests&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;เกิน rate limit&lt;/td&gt;
&lt;td&gt;รอ ~1 นาที — Garudust retry อัตโนมัติ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent ตอบภาษาอังกฤษตลอด&lt;/td&gt;
&lt;td&gt;ยังไม่ได้ตั้ง memory&lt;/td&gt;
&lt;td&gt;บอกครั้งเดียว: "ตอบเป็นภาษาไทยเสมอ"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent ไม่เรียก tool&lt;/td&gt;
&lt;td&gt;โมเดลข้าม tool call&lt;/td&gt;
&lt;td&gt;ระบุชัดขึ้น: "ใช้ web_search หา..." หรือเปลี่ยนเป็น 30B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Context เกิน&lt;/td&gt;
&lt;td&gt;prompt ยาวเกินไป&lt;/td&gt;
&lt;td&gt;ลด &lt;code&gt;context_window&lt;/code&gt; หรือเปิด compression&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Config สรุปฉบับสมบูรณ์
&lt;/h2&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="c1"&gt;# --- LLM ---&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="na"&gt;base_url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://api.opentyphoon.ai/v1&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;typhoon-v2.1-12b-instruct&lt;/span&gt;    &lt;span class="c1"&gt;# หรือ typhoon-v2.5-30b-a3b-instruct&lt;/span&gt;

&lt;span class="c1"&gt;# --- Context ---&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;8192&lt;/span&gt;                &lt;span class="c1"&gt;# 8192 สำหรับ 12B, 32768 สำหรับ 30B&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;span class="c1"&gt;# --- Memory ---&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;# บันทึก fact ทุก 5 iteration (0 = ปิด)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# ~/.garudust/.env&lt;/span&gt;
&lt;span class="nv"&gt;VLLM_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sk-ty-xxxxxxxxxxxxxxxxxxxxxxxxxxxx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ลิงก์ที่เกี่ยวข้อง
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Garudust:&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;Typhoon API:&lt;/strong&gt; &lt;a href="https://opentyphoon.ai" rel="noopener noreferrer"&gt;opentyphoon.ai&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Typhoon Docs:&lt;/strong&gt; &lt;a href="https://docs.opentyphoon.ai" rel="noopener noreferrer"&gt;docs.opentyphoon.ai&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Typhoon Rate Limits:&lt;/strong&gt; &lt;a href="https://docs.opentyphoon.ai/en/rate-limits/" rel="noopener noreferrer"&gt;docs.opentyphoon.ai/en/rate-limits&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Garudust 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;/ul&gt;




&lt;p&gt;&lt;em&gt;Garudust + Typhoon = AI agent ที่รันบน hardware ของคุณเอง พูดภาษาไทยได้ดี และไม่ส่งข้อมูลออกนอกบ้านถ้าคุณ self-host Typhoon เอง&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>ai</category>
      <category>thaillm</category>
      <category>selfhosted</category>
    </item>
    <item>
      <title>Garudust: A Self-Improving AI Agent Runtime Built in Rust</title>
      <dc:creator>Garudust</dc:creator>
      <pubDate>Wed, 13 May 2026 08:31:13 +0000</pubDate>
      <link>https://forem.com/garudust/garudust-a-self-improving-ai-agent-runtime-built-in-rust-1j09</link>
      <guid>https://forem.com/garudust/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>Garudust</dc:creator>
      <pubDate>Wed, 13 May 2026 08:07:57 +0000</pubDate>
      <link>https://forem.com/garudust/build-an-ai-powered-auto-post-bot-for-facebook-with-garudust-430</link>
      <guid>https://forem.com/garudust/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>
