Build Autonomous AI Agents in OpenClaw (with TypeScript Examples)
“Autonomous AI agents” sounds like a buzzword until you ship one that quietly saves you hours every week. The core loop is straightforward:
- Watch for something important (new email, a tech update, a failing container)
- Think (classify, plan, decide what to do next)
- Act (draft a reply, suggest a post, generate code, propose a fix)
- Learn/remember (store decisions, avoid repeat work, keep an audit trail)
OpenClaw is a strong fit for this because it’s built like a personal operations layer: it can schedule recurring tasks (cron), react to events (hooks/webhooks), and deliver output to real channels (Telegram/WhatsApp/etc.).
What you’ll build in this post
- A dedicated Trends Agent with its own workspace + SOUL.md
- An hourly cron job that produces: 5 tech updates + sources + 3 tweet drafts + optional thread
- Telegram delivery (draft-only; no auto-posting)
What “autonomous” should mean (in production)
Autonomy is a spectrum. In real systems, the best agents are usually:
- Semi-autonomous by default: the agent drafts actions and asks for approval.
- Fully autonomous only for low-risk tasks: housekeeping, summaries, formatting, routine checks.
- Auditable: every action is logged and reversible when possible.
- Bounded: strict scope, explicit tools, and clear stop conditions.
A useful mental model is: agent = policy + tools + schedule + guardrails.
Agent set #1: Email agent (read → draft response)
Goal
- Detect new emails (support inquiries, sales leads, vendor messages).
- Classify urgency + topic.
- Draft a reply in your voice with the right context.
Guardrails (recommended)
- Start with draft-only. Don’t auto-send on day one.
- Don’t open attachments automatically.
- For password resets, billing changes, refunds, legal requests: always escalate.
Agent set #2: Latest tech updates → tweet suggestions (hourly)
Goal
- Track latest tech updates (AI, developer tooling, cloud, security, OSS releases).
- Turn them into tweet drafts for X.com.
- Deliver drafts to Telegram for quick review.
Guardrails
- No confidential info.
- Avoid unverifiable claims; include sources.
- Draft-only: do not auto-post.
Agent set #3: Code snippet agent (prompt → generate → validate)
Goal
- Generate correct code snippets (TypeScript utilities, API handlers, Dockerfiles).
- Provide usage examples and edge cases.
Agent set #4: Docker ops agent (observe → report → optionally fix)
Goal
- Identify disk usage (images, volumes, logs).
- Detect unhealthy containers and repeated restarts.
- Propose safe cleanups; require approval for destructive actions.
Step-by-step: Create a dedicated “Trends Agent” workspace (with its own SOUL.md)
If you want your hourly trend/tweet automation to have a different personality and scope than your main assistant, set up a separate agent workspace.
Step 1 - Create a new agent workspace folder
Example (inside your existing OpenClaw workspace mount):
1mkdir -p /mnt/openclaw-workspace/trends-agent/memory 2cp /mnt/openclaw-workspace/AGENTS.md /mnt/openclaw-workspace/trends-agent/AGENTS.md 3cp /mnt/openclaw-workspace/USER.md /mnt/openclaw-workspace/trends-agent/USER.md 4cp /mnt/openclaw-workspace/TOOLS.md /mnt/openclaw-workspace/trends-agent/TOOLS.md
Step 2 - Add a Trends-focused SOUL.md
Create:
1nano /mnt/openclaw-workspace/trends-agent/SOUL.md
Keep it focused. Example rules:
- mission: find latest tech updates + draft X.com posts
- must include sources
- draft-only (never auto-post)
What these agent files are for (SOUL.md, AGENTS.md, USER.md, etc.)
OpenClaw agents don’t “remember” anything unless it’s written down. These files are how you give an agent a stable identity, rules, and continuity.
SOUL.md - persona + behavior rules
The agent’s operating system: tone, boundaries, priorities, what to do/avoid.
AGENTS.md - how the workspace should be run
A workspace playbook: what to read first, safety conventions, and how to operate day-to-day.
TOOLS.md - environment-specific notes
Local facts needed to operate reliably (paths, ports, hostnames). Keep secrets out unless you explicitly want them stored.
USER.md - the human profile (how to help you)
Your preferences (tone, timezone, style) and current goals.
IDENTITY.md - name/emoji/avatar metadata
Optional, but helpful when you run multiple agents so it’s obvious who is who.
MEMORY.md - curated long-term memory
High-signal, stable context (decisions, preferences, long-lived facts).
memory/YYYY-MM-DD.md - daily logs / journal
Raw daily notes. Later, promote important items into MEMORY.md.
Copy/paste templates for a Trends (X.com) agent workspace
If you want a working example you can paste straight into files, here are minimal templates aligned to the hourly tech updates → X.com drafts → Telegram delivery workflow.
SOUL.md (Trends Agent)
1# SOUL.md - Trends Agent 2 3Mission: 4- Every hour, find credible tech updates and draft X.com tweets. 5 6Rules (non-negotiable): 7- Always include sources/links. 8- No unverifiable claims. If unsure, say "unclear" or skip. 9- Draft-only: never auto-post to X.com. 10- Keep tweets <= 280 characters. 11 12Style: 13- Practical, builder-focused, slightly opinionated. 14- Short sentences. No hype. 15 16Output format: 171) 5 updates + links 182) best pick + why 193) Tweet A/B/C 204) optional 4-tweet thread
AGENTS.md (workspace playbook)
1# AGENTS.md (Trends workspace) 2 3## Every session 41) Read SOUL.md, USER.md, latest daily memory. 52) Stay in scope: tech updates + X.com drafts only. 6 7## Safety 8- Never run destructive commands. 9- Never post automatically. 10- Prefer reversible actions.
USER.md (preferences)
1# USER.md 2 3- Name: Jayesh Jain 4- Timezone: UTC (or set your local TZ) 5- Posting style: crisp, practical, no fluff 6- CTA preference: only when relevant ("Read more", "Try it", etc.)
TOOLS.md (where/how to deliver)
1# TOOLS.md 2 3### Telegram 4- Primary destination: telegram:<your_chat_id> 5 6### X.com 7- Posting: manual only (drafts delivered to Telegram)
IDENTITY.md (optional)
1# IDENTITY.md 2 3- Name: Trends Agent 4- Creature: Scout 5- Vibe: concise, evidence-driven 6- Emoji: 🛰️
MEMORY.md (curated long-term rules)
1# MEMORY.md 2 3## Writing rules 4- Avoid hashtags unless essential. 5- Prefer one strong insight per tweet. 6 7## Topics to prioritize 8- AI agents, developer tooling, cloud infra, security advisories, notable OSS releases.
memory/YYYY-MM-DD.md (daily log example)
1# 2026-02-13 2 3- Picked: <best update> 4- Tweet chosen: Option B 5- Notes: audience liked practical benchmark angle
Step-by-step: Register the Trends Agent in OpenClaw
Edit ~/.openclaw/openclaw.json and add a second agent entry:
1{ 2 agents: { 3 list: [ 4 { id: "main", default: true, workspace: "/mnt/openclaw-workspace" }, 5 { id: "trends", name: "Trends Agent", workspace: "/mnt/openclaw-workspace/trends-agent" } 6 ] 7 } 8}
Restart the gateway after config changes:
1openclaw gateway restart
Step-by-step: Add an hourly “Latest Tech → X.com Tweet Suggestions” cron job (deliver to Telegram)
This section shows the exact cron job setup. It assumes:
- Telegram bot is configured and you’ve paired/allowed your chat ID
- your OpenClaw instance can retrieve web pages (via sandbox browser if you’re in Docker)
Step 1 - Create the cron job (every 1 hour)
1openclaw cron add \ 2 --name "Latest tech → X.com tweet suggestions (hourly)" \ 3 --every-ms 3600000 \ 4 --session isolated \ 5 --message "You are my tech news + X.com copy assistant.\n\nRun hourly:\n1) Find 5 latest notable tech updates from the last 24-48 hours (AI + dev tools + cloud + security + OSS).\n2) Include a source link for each.\n3) Pick the best ONE update to tweet about (explain why it’s most interesting/valuable).\n4) Draft 3 tweet options (each <= 280 chars) with different angles: (a) practical takeaway, (b) opinionated take, (c) mini-summary + what to do next.\n5) Provide an optional 4-tweet thread version.\n\nRules:\n- Draft-only. Do NOT post automatically.\n- No confidential info.\n- No unverifiable claims; if unsure, frame as opinion or ask for confirmation.\n- Output in plain text with clear separators." \ 6 --announce \ 7 --channel telegram \ 8 --to "telegram:<telegram_chat_id>"
Step 2 - Verify and test
1openclaw cron list 2openclaw cron run <job-id> 3openclaw cron runs --id <job-id>
Step 3 - Bind the cron job to the Trends agent
Bind the job to agentId: "trends" so it runs with the Trends Agent’s SOUL.md and workspace.
TypeScript example: Turn a trend into an X.com post (draft + approval)
Below is a practical TypeScript pattern you can use inside your codebase to generate a tweet (or thread) from a selected trend, without auto-posting.
It’s intentionally split into two steps:
- Generate a draft tweet from a trend + source URL
- Human approval before anything is posted to X
1) Define the input + output
1type TrendItem = { 2 title: string; 3 url: string; 4 bullets: string[]; // 2-5 key facts 5}; 6 7type TweetDraft = { 8 bestPickWhy: string; 9 tweetOptions: { 10 style: "practical" | "opinionated" | "summary"; 11 text: string; // <= 280 chars 12 }[]; 13 thread?: string[]; // each tweet <= 280 chars 14};
2) Generate tweet drafts from a trend (LLM call)
1interface LlmClient { 2 complete(opts: { 3 system: string; 4 user: string; 5 temperature?: number; 6 }): Promise<string>; 7} 8 9const SYSTEM = ` 10You write X.com drafts for a tech audience. 11Rules: 12- Output JSON only. 13- Every claim must be supported by the provided bullets. 14- Each tweet must be <= 280 characters. 15- No hashtags unless they add real value. 16- Draft-only: do not instruct posting automation. 17`.trim(); 18 19export async function draftTweetsFromTrend(llm: LlmClient, trend: TrendItem): Promise<TweetDraft> { 20 const user = ` 21Trend: 22- Title: ${trend.title} 23- Source: ${trend.url} 24- Facts:\n${trend.bullets.map((b) => `- ${b}`).join("\n")} 25 26Task: 271) Explain why this is the best trend to tweet today. 282) Draft 3 tweet options (practical/opinionated/summary). 293) Provide an optional 4-tweet thread. 30 31Return JSON matching TweetDraft. 32`.trim(); 33 34 const raw = await llm.complete({ system: SYSTEM, user, temperature: 0.4 }); 35 return JSON.parse(raw) as TweetDraft; 36}
3) Approval loop (example)
Your cron job can deliver the drafts to Telegram. You reply with:
- “Use option #2”
- “Rewrite option #1 more technical”
Only after that should you post to X (manual is safest to start).
Common failure mode: no web retrieval (especially in Docker)
If the agent can’t browse/search, it should refuse to invent sources.
When running OpenClaw in Docker, the recommended fix is the sandbox browser:
- Build the browser sandbox image:
1scripts/sandbox-browser-setup.sh
- Enable it:
1{ 2 agents: { 3 defaults: { 4 sandbox: { browser: { enabled: true, autoStart: true } } 5 } 6 } 7}
- Restart:
1openclaw gateway restart
A practical TypeScript example: “Autonomous Email Draft Agent”
Below is a practical TypeScript agent skeleton that demonstrates the pattern:
- fetch work items (new emails),
- run an LLM step to classify + draft,
- output structured results you can route to a chat surface.
Note: the exact OpenClaw SDK/API surface depends on your deployment. Treat this as an application-level pattern you can run inside an OpenClaw isolated job.
Types + prompt discipline (structured output)
1// email-agent.ts 2type EmailMessage = { 3 id: string; 4 from: string; 5 subject: string; 6 receivedAt: string; // ISO 7 text: string; 8}; 9 10type DraftResult = { 11 emailId: string; 12 urgency: "low" | "medium" | "high"; 13 category: "sales" | "support" | "billing" | "partnership" | "unknown"; 14 summaryBullets: string[]; 15 draftSubject: string; 16 draftBody: string; 17 questionsForHuman?: string[]; 18 safeToAutoSend: boolean; 19}; 20 21const SYSTEM_POLICY = ` 22You are an assistant that drafts email responses. 23Rules: 24- Never claim you performed actions you didn't do. 25- If the email requests credentials, payment changes, refunds, or legal statements: set safeToAutoSend=false and add questionsForHuman. 26- Keep tone professional, concise, helpful. 27- Output MUST be valid JSON matching the DraftResult type. 28`.trim(); 29 30function buildUserPrompt(email: EmailMessage) { 31 return ` 32Email: 33From: ${email.from} 34Subject: ${email.subject} 35ReceivedAt: ${email.receivedAt} 36 37Body: 38${email.text} 39 40Task: 411) Classify urgency + category 422) Summarize in 2-5 bullets 433) Produce a reply draft (subject + body) 444) Ask clarifying questions if needed 455) Set safeToAutoSend=false unless it's a trivial acknowledgement. 46`.trim(); 47}
LLM call (provider-agnostic pattern)
1interface LlmClient { 2 complete(opts: { 3 system: string; 4 user: string; 5 temperature?: number; 6 }): Promise<string>; 7} 8 9function safeJsonParse<T>(raw: string): T { 10 const first = raw.indexOf("{"); 11 const last = raw.lastIndexOf("}"); 12 if (first === -1 || last === -1) throw new Error("No JSON object found."); 13 return JSON.parse(raw.slice(first, last + 1)); 14} 15 16export async function draftRepliesForEmails(opts: { 17 llm: LlmClient; 18 emails: EmailMessage[]; 19}): Promise<DraftResult[]> { 20 const results: DraftResult[] = []; 21 22 for (const email of opts.emails) { 23 const raw = await opts.llm.complete({ 24 system: SYSTEM_POLICY, 25 user: buildUserPrompt(email), 26 temperature: 0.3, 27 }); 28 29 const parsed = safeJsonParse<DraftResult>(raw); 30 31 // Hard guardrail: never allow auto-send initially. 32 parsed.safeToAutoSend = false; 33 34 results.push(parsed); 35 } 36 37 return results; 38}




