e (Telegram), the orchestration layer (Garudust Agent), and the execution target (Raspberry Pi). The agent runs on a cloud VPS or always-on server, maintaining a persistent Telegram webhook. When a message arrives, the LLM parses intent, selects the appropriate tool, and routes it through the SSH sandbox layer. The sandbox transparently wraps every command in an ssh call, ensuring the target device remains unaware of the orchestration mechanism.
Step 1: Isolate Execution Credentials
Never reuse personal or root credentials for automated agents. Generate a dedicated Ed25519 key pair scoped exclusively to the orchestration workflow:
ssh-keygen -t ed25519 -f ~/.ssh/edge_orchestrator_key -N "" -C "garudust-remote-agent"
Deploy the public key to the Raspberry Pi using a restricted authorized_keys entry. This limits the agent to specific command patterns and prevents arbitrary shell access:
cat ~/.ssh/edge_orchestrator_key.pub | ssh pi@10.0.4.22 "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
Validate the connection with strict mode enforcement:
ssh -i ~/.ssh/edge_orchestrator_key \
-o BatchMode=yes \
-o StrictHostKeyChecking=accept-new \
pi@10.0.4.22 "hostname && uptime"
The agent requires two configuration files: a secrets store and a runtime manifest. Secrets are isolated in a .env file to prevent leakage into version control or process listings:
# ~/edge-orchestrator/.env
PROVIDER_API_KEY=sk-ant-prod-xxxxxxxxxxxx
TELEGRAM_BOT_TOKEN=712345678:AAHxxxxxxxxxxxxxxxxxxxxxxx
The runtime manifest defines routing, security policies, and platform bindings. The terminal_sandbox directive instructs the agent to intercept all shell tool calls and forward them via SSH:
# ~/edge-orchestrator/runtime.yaml
security:
approval_policy: smart
terminal_sandbox: ssh
ssh_target:
host: "10.0.4.22"
user: "pi"
port: 22
identity_file: "/home/deploy/.ssh/edge_orchestrator_key"
connection_opts:
batch_mode: true
strict_host_key: "accept-new"
platforms:
telegram:
enabled: true
webhook_port: 9000
callback_path: "/webhook/edge"
access_control:
default_role: restricted
roles:
admin:
approval_policy: auto
users:
telegram:
"884729103": admin
Step 3: Design Idempotent Execution Wrappers
The agent executes commands as they are received. To prevent race conditions and ensure predictable behavior, wrap hardware interactions in idempotent scripts. Instead of raw gpio commands, use a structured Python wrapper that validates state before mutation:
#!/usr/bin/env python3
# ~/scripts/edge_ctl/gpio_manager.py
import sys
import time
from gpiozero import LED, Button
from signal import pause
class GPIOController:
def __init__(self):
self.relay_18 = LED(18)
self.relay_23 = LED(23)
self.status_led = LED(25)
def set_state(self, pin: int, action: str) -> dict:
target = getattr(self, f"relay_{pin}", None)
if not target:
return {"status": "error", "message": f"Pin {pin} not configured"}
if action == "on":
target.on()
elif action == "off":
target.off()
else:
return {"status": "error", "message": "Invalid action"}
return {"status": "success", "pin": pin, "state": action}
if __name__ == "__main__":
if len(sys.argv) != 3:
print("Usage: gpio_manager.py <pin> <on|off>")
sys.exit(1)
controller = GPIOController()
result = controller.set_state(int(sys.argv[1]), sys.argv[2])
print(result)
Architecture Rationale
The SSH sandbox layer is the critical differentiator. By intercepting tool calls at the agent level, you maintain a single execution interface regardless of the target environment. The agent does not need to know whether it's running locally or remotely; the sandbox handles routing, environment sanitization, and connection lifecycle.
The smart approval policy is deliberately chosen for production. Read-only operations (sensor polling, log inspection, system metrics) bypass confirmation to maintain low-latency telemetry. State-mutating commands (GPIO toggling, service restarts, file writes) trigger an explicit approval request. This balances automation efficiency with operational safety, preventing accidental hardware damage or service disruption.
Telegram's webhook architecture ensures the agent remains stateless and scalable. Messages are pushed to the server, processed asynchronously, and responses are routed back through the bot API. This eliminates polling overhead and aligns with modern event-driven patterns.
Pitfall Guide
1. Credential Sprawl Across Environments
Explanation: Reusing personal SSH keys or embedding credentials in configuration files leads to unauthorized access if the agent is compromised or logs are leaked.
Fix: Generate dedicated Ed25519 keys per agent instance. Store secrets exclusively in .env files with 600 permissions. Rotate keys quarterly and revoke immediately upon personnel changes.
2. Disabling Host Key Verification
Explanation: Setting StrictHostKeyChecking=no allows man-in-the-middle attacks by accepting any host fingerprint without validation.
Fix: Use accept-new for initial provisioning, then pin the known host fingerprint in ~/.ssh/known_hosts. Never disable verification in production.
3. Over-Reliance on Auto-Approval
Explanation: Setting approval_policy: auto for all users removes the safety net for destructive commands, increasing the risk of accidental service restarts or hardware misconfiguration.
Fix: Reserve auto for trusted admin accounts only. Maintain smart or manual for standard users. Implement audit logging to track all approved mutations.
4. Hardcoding Absolute Paths in Prompts
Explanation: The LLM may generate commands with incorrect or environment-specific paths, causing execution failures or unintended file modifications.
Fix: Use relative paths, wrapper scripts, or environment variables. Validate paths in the agent's tool definition layer before execution.
5. Ignoring Environment Isolation
Explanation: The agent's subprocess environment may leak API keys, tokens, or internal variables to the SSH session, compromising the target device.
Fix: Ensure the sandbox clears os.environ before spawning ssh. Use env -i ssh or explicit environment filtering in the agent configuration.
6. Misaligned Timezone Schedules
Explanation: Cron-like scheduled tasks default to UTC, causing misaligned reporting windows or delayed alerts for local operations.
Fix: Explicitly define timezone in the scheduler configuration. Validate schedule expressions against the target region's daylight saving rules.
7. Exposing SSH to Public Networks
Explanation: Opening port 22 to 0.0.0.0 invites brute-force attacks and unauthorized scanning, even with key-based authentication.
Fix: Restrict SSH access to the agent's static IP using iptables or cloud security groups. Implement fail2ban and disable password authentication entirely.
Production Bundle
Action Checklist
Decision Matrix
| Scenario | Recommended Approach | Why | Cost Impact |
|---|
| Single Pi, home lab | Local VPS + Telegram Agent | Zero inbound ports, minimal setup | $0-5/mo (VPS) |
| Multi-site edge fleet | Centralized Agent + SSH Bastion | Unified control plane, audit trails | $10-20/mo (VPS + bandwidth) |
| High-security industrial | VPN Mesh + Custom Dashboard | Full network isolation, compliance | $50+/mo (infrastructure + dev) |
| Rapid prototyping | Direct SSH + tmux | Immediate access, no abstraction | $0 (developer time only) |
Configuration Template
# ~/edge-orchestrator/production.yaml
security:
approval_policy: smart
terminal_sandbox: ssh
ssh_target:
host: "10.0.4.22"
user: "pi"
port: 22
identity_file: "/home/deploy/.ssh/edge_orchestrator_key"
connection_opts:
batch_mode: true
strict_host_key: "accept-new"
server_alive_interval: 60
server_alive_count_max: 3
platforms:
telegram:
enabled: true
webhook_port: 9000
callback_path: "/webhook/edge"
rate_limit:
requests_per_minute: 30
burst_size: 5
access_control:
default_role: restricted
roles:
admin:
approval_policy: auto
operator:
approval_policy: smart
users:
telegram:
"884729103": admin
"991827364": operator
scheduler:
timezone: "America/New_York"
jobs:
- schedule: "0 8 * * *"
task: "collect system metrics and send morning report"
- schedule: "*/15 * * * *"
task: "poll temperature sensor; alert if > 75C"
Quick Start Guide
- Provision Credentials: Generate a dedicated SSH key pair and deploy the public key to your Raspberry Pi. Verify connectivity using
BatchMode=yes and StrictHostKeyChecking=accept-new.
- Deploy Agent Binary: Download the latest Garudust release, extract the binaries, and place
garudust-server in your system path. Create the ~/edge-orchestrator/ directory structure.
- Configure Secrets & Runtime: Populate
.env with your provider API key and Telegram bot token. Copy the production YAML template, update the SSH target IP, and assign your Telegram user ID to the admin role.
- Launch & Validate: Start the server with
garudust-server. Send a test message via Telegram requesting a simple read-only command (e.g., uptime). Verify the response routes through SSH and returns correctly.
- Enable Scheduled Tasks: Add a cron-like job to the scheduler configuration. Restart the agent and confirm the first automated report arrives in your Telegram chat within the expected window.