- Jinja 100%
|
|
||
|---|---|---|
| docs | ||
| inventory | ||
| playbooks | ||
| roles | ||
| .gitignore | ||
| ansible.cfg | ||
| README.md | ||
| requirements.yml | ||
dooc
Ansible automation to deploy an OpenClaw AI agent with its own Telegram bot, email inbox, and git account — each a real, independent identity the agent owns.
What it does
- Deploys OpenClaw to a DigitalOcean Droplet or an existing Kubernetes cluster
- Gives the agent its own Telegram bot identity
- Gives the agent its own email inbox via AgentMail.to
- Gives the agent its own Forgejo user account on any self-hosted Forgejo instance — unique username, scoped API token, no shared admin creds. The agent opens issues, creates repos, and submits PRs under its own name, with its own audit trail (optional)
- Picks an LLM mode per agent: OpenRouter (budget-capped), DeepSeek direct (cheap + fast), user-hosted Ollama, or self-hosted vLLM on a DO GPU Droplet
- Supports multiple agents side-by-side in one k8s namespace (distinct Telegram/email/Forgejo identities, distinct workspace PVCs)
- Tears everything down cleanly with a single command
Prerequisites
- Python 3.10+
- Ansible 2.15+ —
pip install ansible - community.digitalocean collection — installed automatically via
requirements.yml - A DigitalOcean account with an API token (read+write)
- An SSH key uploaded to your DO account
- A Telegram bot created via @BotFather
- An AgentMail.to account with an API key
- An OpenRouter account with an API key — set a budget limit on the key at Settings > Keys (daily, weekly, or monthly cap)
Quick start
1. Install dependencies
pip install ansible
ansible-galaxy collection install -r requirements.yml
2. Prepare external accounts
Before deploying, set up these services (5-10 minutes):
- DigitalOcean — create an API token with read+write scope, and upload an SSH key
- Telegram — message @BotFather, send
/newbot, save the token. Then message @userinfobot to get your numeric user ID - AgentMail — sign up at agentmail.to, create an inbox, and get an API key
- OpenRouter — sign up at openrouter.ai, create an API key, and set a budget limit on it at Settings > Keys
3. Configure
cp inventory/hosts.ini.example inventory/hosts.ini
Edit inventory/hosts.ini and fill in:
| Variable | Where to get it |
|---|---|
do_api_token |
DigitalOcean API settings |
do_ssh_key_name |
Name of your SSH key in DO (e.g., mykey) |
telegram_bot_token |
@BotFather after creating your bot |
telegram_user_id |
@userinfobot — must be numeric (e.g., 123456789) |
agentmail_inbox_email |
Your pre-created inbox address (e.g., mybot@agentmail.to) |
agentmail_api_key |
AgentMail dashboard |
openrouter_api_key |
OpenRouter dashboard — ensure budget limit is set |
4. Deploy
ansible-playbook playbooks/deploy.yml
This validates your credentials, provisions a DO Droplet, and starts OpenClaw. Your Telegram bot will be online in about 2 minutes.
5. Tear down
ansible-playbook playbooks/destroy.yml
Destroys the Droplet and cleans up. Your AgentMail inbox and Telegram bot are preserved for reuse.
Security
This is a public repo. Never commit secrets.
- Your
inventory/hosts.iniis gitignored — it holds all credentials - The committed
hosts.ini.examplecontains only placeholder values - Consider using ansible-vault to encrypt your inventory at rest
LLM provider and budget
By default, dooc uses OpenRouter in API mode with anthropic/claude-sonnet-4. You can change the model in group_vars/all.yml — see that file for pricing and budget guidance.
You must set a budget limit on your OpenRouter API key. This is a hard cap — requests are rejected when the limit is hit, so there are no surprise charges. Configure it at OpenRouter Settings > Keys.
Cheaper alternatives with tool-calling support:
| Model | Input / Output (per 1M tokens) | Notes |
|---|---|---|
anthropic/claude-sonnet-4 |
$3 / $15 | Default — reliable tool-calling |
google/gemini-2.5-flash-lite |
$0.25 / $1.50 | Good budget option |
deepseek/deepseek-v3.2 |
$0.28 / $0.42 | Cheapest for code tasks |
openai/gpt-4o-mini |
$0.15 / $0.60 | Cheapest cloud, weaker on complex chains |
DeepSeek direct mode
For significantly cheaper inference than OpenRouter while keeping an official, paid upstream, set llm_mode=deepseek. Uses DeepSeek's OpenAI-compatible API directly.
llm_mode=deepseek
deepseek_api_key=YOUR_DEEPSEEK_API_KEY
deepseek_model=deepseek-chat
DeepSeek V3.2 via direct API runs ~$0.28/$0.42 per 1M tokens (cache-miss input / output) with automatic prompt caching dropping cache-hit input to ~$0.07 per 1M. Get a key at platform.deepseek.com/api_keys and watch usage at platform.deepseek.com/usage.
Works with both DO Droplet and Kubernetes deploy targets.
Self-hosted GPU mode
For zero per-token cost, set llm_mode=gpu in your inventory. This provisions a DO GPU Droplet running vLLM with tool-calling enabled. OpenClaw reaches vLLM over DO's private VPC network.
# Deploy with GPU mode
ansible-playbook playbooks/deploy.yml -e llm_mode=gpu
GPU Droplets start at ~$3.19/hr (1x H100). The default model is Qwen/Qwen3-Coder-480B-A35B (MoE, fits single H100). See group_vars/all.yml for alternatives.
Kubernetes deployment (homelab)
Deploy to an existing Kubernetes cluster instead of DigitalOcean. Works with any conformant k8s distribution (k3s, k8s, etc.).
# Deploy to k8s with Ollama
ansible-playbook playbooks/deploy-k8s.yml
# Tear down
ansible-playbook playbooks/destroy-k8s.yml
Set llm_mode=ollama and ollama_base_url in your inventory to point at your local Ollama instance. The same custom Docker image is used — no separate build needed.
Requires kubectl configured and the kubernetes.core Ansible collection (ansible-galaxy collection install -r requirements.yml).
Running multiple agents in one namespace
Every k8s resource is prefixed with agent_name (default dooc), so multiple agents coexist in one namespace without collision. Each agent should have its own inventory file with unique agent_name, telegram_bot_token, agentmail_inbox_email, and (if used) forgejo_agent_username:
agent_name=dooc2
Standard k8s labels make it easy to slice:
# All dooc agents
kubectl get all -n dooc -l app.kubernetes.io/part-of=dooc
# One specific agent
kubectl get all -n dooc -l app.kubernetes.io/instance=dooc2
Ollama mode
For self-hosted inference on your own hardware with zero cost:
llm_mode=ollama
ollama_base_url=http://192.168.50.100:11434
ollama_model=qwen3-coder-next
Works with both DO and k8s deployment targets. Uses the native Ollama API (not /v1) for reliable tool calling.
Forgejo git identity for the agent (optional)
If you run a self-hosted Forgejo instance, dooc gives the agent its own full Forgejo user account — not a shared service token, not a bot role bolted onto your personal account. A real user with a real username, a scoped API token, and its own activity feed.
Why it matters:
- Audit trail. Every commit, issue comment, PR, and repo creation shows the agent as author. You can see exactly what the agent did and when, separately from your own work.
- Least privilege. The agent's token is scoped to
repoandissueread/write only — no admin, no user management, no ability to escalate. - Revocable without fallout. Destroy the agent user and its token disappears with it. Your admin credentials stay yours.
- Works on any Forgejo. The
forgejo_agentrole uses only the standard Forgejo admin API — no Forgejo version pinning, no custom patches.
Inside the container, the agent uses the fj CLI (Forgejo's gh equivalent, pre-installed and auto-authenticated) to create repos, open issues, comment, and submit PRs under its own name.
To enable, uncomment and fill in the Forgejo section in your inventory/hosts.ini:
forgejo_agent_enabled=true
forgejo_url=https://git.example.com
forgejo_admin_token=YOUR_ADMIN_TOKEN
forgejo_agent_username=dooc1
forgejo_agent_email=dooc1@agentmail.to
The agent user is created on deploy and purged on teardown (cascades to its repos, tokens, and issues). Multiple agents get distinct Forgejo users — use a unique forgejo_agent_username per inventory file.
Customizing your agent
OpenClaw uses a SOUL.md file to define the agent's personality. A default "technical cofounder" personality ships with dooc. To customize:
- Set
soul_md_contentin yourinventory/hosts.inito override the default entirely - Or edit
roles/openclaw/defaults/main.ymlto change thesoul_md_default
Project structure
dooc/
├── ansible.cfg # Ansible configuration
├── requirements.yml # Ansible collection dependencies
├── inventory/
│ ├── hosts.ini.example # Credential template (copy to hosts.ini)
│ └── group_vars/
│ └── all.yml # Default settings (region, size, mode, model, SOUL.md)
├── roles/
│ ├── droplet/ # Provision/destroy DO compute droplet
│ ├── gpu_droplet/ # Provision/destroy DO GPU droplet (GPU mode)
│ ├── agentmail/ # Create/destroy AgentMail email inbox
│ ├── llm_provider/ # Validate LLM provider config (API or GPU mode)
│ ├── vllm/ # Deploy vLLM inference server on GPU droplet
│ ├── forgejo_agent/ # Create/destroy Forgejo user account for the agent (optional)
│ ├── openclaw/ # Install Docker, deploy OpenClaw container (DO target)
│ └── k8s_openclaw/ # Deploy OpenClaw as k8s Deployment (k8s target)
├── playbooks/
│ ├── deploy.yml # DO deployment
│ ├── destroy.yml # DO teardown
│ ├── deploy-k8s.yml # Kubernetes deployment
│ └── destroy-k8s.yml # Kubernetes teardown
└── docs/
├── ARCHITECTURE.md # System design
└── ROADMAP.md # Current state and next steps