You can spend ten minutes every morning hunting for the right Headspace track, or you can let an agent build the session for you—matched to last night’s sleep score, spoken in your preferred voice, and mixed with a rainstorm from the forest you miss. The rest of this post is how I wired that up with OpenClaw, ElevenLabs, and a couple of boring JSON files.
Why bother automating a meditation routine at all?
Meditation apps are fine until they’re not. They ask you what you want while you’re already decision-fatigued, their scripts never reference your life, and they have zero API surface to extend. OpenClaw gives us programmatic control:
- Pull yesterday’s stress and HRV data from Oura, Apple Health, or Google Fit
- Generate a tailored script: “Focus on letting go of the meeting with Alice…”
- Synthesize that script with ElevenLabs TTS in a voice you actually like
- Blend in an ambient track generated on-the-fly (or reused from a cache)
- Ship the final MP3 to WhatsApp/Telegram or just auto-play on your laptop
- Schedule all of it—no buttons, no app launch, no excuses
This article walks through my exact stack: Node 22.4, openclaw 2.1.3, ElevenLabs API v1, and a tiny wrapper around sox for audio merging. Copy/paste at will.
Prerequisites: accounts, tokens, and one sanity check
- Node 22+.
nvm install 22 && nvm use 22 - OpenClaw CLI.
npm i -g openclaw - ClawCloud account if you don’t want to run local. I tested both.
- ElevenLabs API key with TTS credits. The free tier is enough for one meditation a day.
- Ambient audio generator. I use Bark with the “nature_rain” preset. Any WAV will do.
- Mood data source. I’ll pull from Oura Cloud, but Apple Health via HealthKit or Google Fit via REST is the same pattern.
If you’re on Windows, make sure sox is in %PATH%. Mac/Linux usually ship it via brew install sox or apt-get install sox.
Scaffolding an OpenClaw agent for wellness automation
Create a new agent. Local run shown below; replace --local with --cloud to host on ClawCloud.
openclaw init meditate-bot --template typescript --local
cd meditate-bot
npm install
The template spits out a daemon.ts and gateway.ts. We’ll add two modules:
scriptWriter.ts– generates the meditation textaudioAssembler.ts– TTS + ambience mashup
Make them discoverable by updating openclaw.config.json:
{
"tools": [
"./scriptWriter.ts",
"./audioAssembler.ts"
],
"schedule": [
{
"cron": "0 6 * * *", // 06:00 every day
"task": "createAndSendSession"
}
]
}
Integrating ElevenLabs TTS in OpenClaw
Community scripts float around GitHub, but I wanted TypeScript types and retries, so here’s my minimal wrapper:
// audioAssembler.ts
import fetch from 'node-fetch';
import { writeFileSync } from 'fs';
const ELEVEN_KEY = process.env.ELEVEN_KEY as string;
const VOICE = 'Rachel'; // pick from Eleven dashboard
export async function tts(text: string, outFile: string) {
const res = await fetch(`https://api.elevenlabs.io/v1/text-to-speech/${VOICE}`, {
method: 'POST',
headers: {
'xi-api-key': ELEVEN_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
text,
model_id: 'eleven_multilingual_v1',
voice_settings: { stability: 0.3, similarity_boost: 0.8 }
})
});
if (!res.ok) throw new Error(`TTS failed: ${res.status}`);
const arrayBuffer = await res.arrayBuffer();
writeFileSync(outFile, Buffer.from(arrayBuffer));
}
Yes, ElevenLabs streams audio chunks. For a <5-min meditation it’s safe to buffer the whole thing; I haven’t hit timeouts.
Merging TTS with ambient audio
sox can layer tracks with a single command:
sox -m voice.mp3 rain.wav output.mp3 gain -n -5
I call it from Node once the TTS MP3 is ready:
import { execSync } from 'child_process';
export function merge(voice: string, ambience: string, out: string) {
execSync(`sox -m ${voice} ${ambience} ${out} gain -n -5`);
}
This is CPU-light; a Raspberry Pi 4 finishes in ~3 s.
Generating the meditation script based on mood and stress
Here the agent must think. I tried direct GPT-4 calls but settled on an OpenAI function calling setup so OpenClaw can chain it with other tools.
// scriptWriter.ts
import { openai } from 'openclaw/plugins';
import { fetchOuraScore } from './oura.js';
export async function buildScript() {
const { hrvTrend, sleepScore } = await fetchOuraScore();
const prompt = `You are a meditation coach.
User HRV trend: ${hrvTrend}.
Sleep score: ${sleepScore}.
Write a 4-minute guided meditation. Focus on letting go of stress.
Use casual but mindful language.`;
const resp = await openai.chat({
model: 'gpt-4o-mini',
messages: [{ role: 'user', content: prompt }],
temperature: 0.7
});
const text = resp.choices[0].message.content as string;
return text;
}
Replace with whichever model token price you can stomach. The agent passes buildScript() output to tts().
Fetching Oura Cloud metrics
// oura.js
import fetch from 'node-fetch';
export async function fetchOuraScore() {
const key = process.env.OURA_KEY;
const res = await fetch('https://api.ouraring.com/v2/usercollection/daily_readiness?start_date=today-1', {
headers: { Authorization: `Bearer ${key}` }
});
const json = await res.json();
return {
hrvTrend: json.data[0].hrv_balance_score,
sleepScore: json.data[0].sleep_balance_score
};
}
Apple HealthKit export is a local SQLite; parse similarly.
Wiring the full workflow in a single task
Add this to daemon.ts:
import { buildScript } from './scriptWriter.js';
import { tts, merge } from './audioAssembler.js';
import { sendToTelegram } from 'openclaw/plugins';
export async function createAndSendSession() {
const text = await buildScript();
await tts(text, '/tmp/voice.mp3');
// reuse cached rain.wav or generate new
const ambience = '/tmp/rain.wav';
if (!existsSync(ambience)) generateRain(ambience);
merge('/tmp/voice.mp3', ambience, '/tmp/final.mp3');
await sendToTelegram('/tmp/final.mp3', {
chatId: process.env.TELEGRAM_CHAT
});
console.log('Meditation delivered');
}
That’s the entire pipeline: data → prompt → TTS → merge → deliver. The cron entry in openclaw.config.json triggers it at 06:00.
Running and debugging locally
Fire up the agent with verbose logs:
openclaw daemon --debug
Watch for common snags:
- ElevenLabs 429s. You’re rate-limited; back-off and retry.
- TTS model mismatch. Some voices only support v2 models; check dashboard.
- sox not found. Ensure the binary path is correct or use FFmpeg with equivalent flags.
- Telegram file too large. Compress or switch to WhatsApp where 16 MB is allowed.
Once stable, deploy to ClawCloud:
openclaw deploy --project meditate-bot
The build server pulls your repo, injects environment variables from the ClawCloud UI, and spins up both gateway and daemon containers in ≈ 45 s.
Scheduling variations: weekday vs weekend, noon reset, and more
OpenClaw’s scheduler supports multiple cron blocks. I added a shorter lunchtime reset during weekdays:
"schedule": [
{ "cron": "0 6 * * *", "task": "createAndSendSession" },
{ "cron": "30 12 * * 1-5", "task": "createAndSendSession", "args": { "duration": 180 } }
]
The args object is passed through to buildScript(), letting it choose a 3-minute script midday. For weekends, the cron expression * * * * 6,0 targets Saturday and Sunday—easy.
Going further: the wellness automation pattern
Once the basics worked, I started chaining other tools:
- Calendar block. Using Composio’s Google Calendar integration I create an “Uninterruptible: Meditation” entry to mute Slack.
- Airplane mode. A shell tool on macOS (
networksetup -setairportpower) toggled by OpenClaw’sshellplugin. - Post-session log. A Notion page with mood emoji. Helps the agent refine prompts over time (persistent memory).
- Ambient variety. Pull a random WAV from a Hugging Face dataset.
The pattern is straightforward:
- Sensors (HRV, sleep, calendar load) feed the agent
- Agent decides content & duration
- Generative components render media
- Output is delivered + environment hardened (DND, calendar block)
- Logs feed back into memory for next time
You can replicate the same skeleton for breathwork, pomodoro breaks, even gratitude journaling.
Security and cost notes
This is not a product brochure, so here are the caveats:
- PII risk. HRV and sleep data are medical. Encrypt at rest; ClawCloud volumes are AES-256 but add your own vault.
- ElevenLabs pricing. 0.3 ¢ per 1K characters. A 4-minute script is ≈600 chars → 0.18 ¢. Cheap but cumulative.
- OpenAI spend. GPT-4o-mini is ~$1.25 per 1M tokens. My daily prompt + completion is 1.2K tokens → 0.15 ¢.
- Scheduler abuse. If someone edits your cron to
* * * * *you’ll burn credits fast. Use OpenClaw’sMAX_TASKS_PER_DAYguard.
On a typical month my entire stack costs under $2, mainly ElevenLabs.
What’s next?
If you built along, tomorrow morning your phone should receive a personalized meditation before Slack pings you. Tweak the script length, voice, or ambient library, then branch into other wellness automations—stretch reminders, journaling, blue-light filter toggles. The agent doesn’t care; it just runs cron. And if you discover a nicer TTS or a cheaper ambience generator, open a PR to the community repo so the next insomniac engineer can copy it.