Before you write any skill code, you need to understand the three-layer stack that powers everything.
01
OpenClaw Gateway
The always-on Node.js process running on the VPS. It's the brain — managing sessions, routing messages, executing skills, and connecting to messaging platforms like WhatsApp.
02
Claude Haiku 4.5 (API)
The LLM that does the thinking. Your skill sends structured prompts to Haiku via the Anthropic API. Haiku reasons, classifies, drafts responses. Your skill acts on the output.
03
Skills
JavaScript files you write that define what an agent can do. Skills are the only thing you directly build. Everything else is infrastructure.
OpenClaw Gateway · MacMini Local (Back-Office Fleet · May 2026)
Claude Haiku 4.5 API
Tailscale · Private Network
02 · Agent Fleet
The WMG agent roster
Click any agent to see their full brief — tools, responsibilities, what they can and can't do, and which skills belong to them.
03 · Skill Structure
Anatomy of a WMG skill
Every skill is a folder. One file is required — the rest are optional but follow a consistent layout. Understand each layer before you start building.
📄 SKILL.md ← required
The entry point. YAML frontmatter holds the skill name and description — this is what the agent reads to decide when to use the skill. The body contains instructions loaded only after the skill triggers. Get the description right first.
🐍 scripts/ ← optional
Tested Python or Bash scripts for deterministic, repeatable tasks. Use when the same logic would otherwise be rewritten from scratch each time. Every script must be tested before committing.
📚 references/ ← optional
Schemas, API docs, WMG-specific logic, lookup tables. Loaded into context only when the agent needs them — keeps SKILL.md lean. If SKILL.md body exceeds ~300 lines, something belongs here instead.
🗂️ assets/ ← optional
Templates, static files, boilerplate code used in output. Not loaded into context — the agent uses these as output materials. Examples: HTML templates, XLSX starters, report layouts.
🔧 config.json ← optional, recommended
Business logic that changes without code changes: contact numbers, thresholds, key account lists, escalation rules, dry_run flag. Non-developers can update this safely without touching SKILL.md or scripts.
---
name: aria-email-triage
description: >
Triage unread emails from aria@wmg-group.com. Classify as URGENT or ROUTINE.
Use when ARIA needs to scan the inbox, escalate critical items to Boss via
WhatsApp, and create tickets for parcel queries, complaints, or pre-alerts.
Triggers on schedule (every 30 min) or when Boss asks ARIA to check email.
---# ARIA Email TriageCheck unread emails, classify priority, alert Boss on URGENT items.## ClassificationURGENT: client complaint, shipment failure, customs hold, key account request,
deadline within 24h, payment dispute 30+ days overdue
ROUTINE: general enquiry, newsletter, automated notification, internal FYI## OutputReturn JSON array. See references/output-schema.md for field definitions.
For URGENT items: send WhatsApp summary to Boss (config.jim_whatsapp).
For parcel queries: create ticket via tickets.wmgai.cloud API.## Rules- When in doubt, classify URGENT
- draft_and_approve: true for any outbound client email
- Never commit funds or approve payments
- Load references/key-accounts.md when checking if sender is a key account## ConfigLoad config.json for thresholds, contact numbers, and dry_run flag.
If dry_run is true, log actions only — do not send or create anything.
# references/output-schema.md — expected output format for email triage
# ARIA reads this when building the classification response.## Triage Response SchemaReturn a JSON array. Each item must have these fields:| Field | Type | Description ||---|---|---|
| id | string | Email message ID from Graph API |
| priority | string | "URGENT" or "ROUTINE" |
| reason | string | One line max — why this classification |
| suggested_action | string | What ARIA should do next |
| ticket_required | boolean | True if a ticket should be created |
| tracking_number | string \| null | WMG tracking number if present in email |## Example[
{
"id": "AAMkAGI...",
"priority": "URGENT",
"reason": "Customer reports parcel undelivered for 14 days",
"suggested_action": "Create ticket, alert Boss, check WMG Connect",
"ticket_required": true,
"tracking_number": "WMG00000816395"
}
]## Notes- tracking_number must be the full WMG format (e.g. WMG00000816395), not truncated
- suggested_action must be actionable, not vague ("follow up" is not acceptable)
- Never include raw email body in response — snippet only
// config.json — business settings only. No code logic here.
// Non-developers can update this safely without touching SKILL.md or scripts.
{
"jim_whatsapp": "+65XXXXXXXX",
"key_accounts": [
"Malaysia Airlines",
"DAI Post Ltd",
"Parxl Pte Ltd"
],
"escalation_threshold_days": 30,
"urgent_keywords": ["customs hold", "cargo damage", "missed deadline"],
"working_hours_sg": { "start": 8, "end": 18 },
"silent_hours_notify": false,
"dry_run": true// always true until Boss confirms production-ready
}
04 · Coding Standards
WMG skill coding standards
These are non-negotiable. Every skill merged to production must follow all of these.
🔒
Least privilege tools
Only expose the tools your skill actually uses. Declare tool access in your skill config — if ARIA's triage skill needs email and WhatsApp, list only those. Never use wildcards or open-ended shell access.
DO: specific tools onlyDON'T: ["*"] or open shell
🛡️
Always catch errors
Every skill must have a try/catch around the ACT phase. On catch, notify CORA with agent name, skill name, and error message. Never let a skill fail silently.
DO: notifyCORA on catchDON'T: silent failures
✅
Draft-and-approve for comms
Any skill that sends messages to clients, partners, or external parties must set "draft_and_approve": true. Boss reviews the draft before it sends. No exceptions for external comms.
Client email → draft firstInternal only → can auto-send
🚫
No financial actions
No skill may initiate, approve, or commit any financial transaction. FINN may draft payment summaries and flag overdue invoices — but never trigger payment. Always requires_approval: true.
Never trigger paymentsDraft + flag only
🧪
Dry-run before enabling
All new skills must pass a dry-run on the MacBook Pro before deployment to the VPS. Set dry_run: true in config.json, review output, then flip to false for production.
MacBook Pro → dry-run → VPSNever skip dry-run
📝
Prompt-first development
Write prompt.md before index.js. Test the prompt manually in Claude.ai with sample data. Only start coding once the LLM output is exactly what you need. Bad prompts waste engineering time.
prompt.md firstDon't code before prompting
💰
Use Haiku, justify Sonnet
All skills default to claude-haiku-4-5. If you believe a task requires Sonnet (complex reasoning, multi-document analysis), document why in a PR comment and get approval before deploying.
Default: HaikuSonnet: needs approval
🧱
One skill, one job
Each skill file does exactly one thing. Email triage is one skill. WhatsApp reply is another. SLA monitoring is another. Don't combine multiple functions — it makes debugging impossible.
One responsibilityNo multi-function skills
05 · Dev Workflow
How to build and ship a skill
Follow this exact sequence every time. No shortcuts.
1
Get a brief from CORA
Every skill starts with a written brief: which agent, what trigger, what tools, what output. If you don't have a brief, ask for one before writing anything.
2
Write and test SKILL.md description first
The description field in SKILL.md frontmatter is the trigger — the agent reads it to decide when to use the skill. Write it before anything else. Test by asking: "Would an agent read this description and correctly know when and how to use this skill?" Then write the body instructions. Only add scripts/ and references/ once the core logic is clear.
Description → body → scripts → references → config
3
Create the skill folder locally
Work locally. Create the folder with SKILL.md at minimum. Add scripts/, references/, assets/, and config.json only as needed. Set dry_run: true in config.json from the start. Never develop directly on the VPS. Use the init script to scaffold: python3 init_skill.py <skill-name>
wmg-[agentname]-[function]/ with SKILL.md + config.json minimum
4
Dry-run on MacBook Pro
Install and run the skill locally. Review every line of output. Check what would have been sent, filed, or actioned. Fix any issues before proceeding.
openclaw skills install [name] && openclaw skills run [name] --dry-run
5
Push to VPS via Tailscale
Once dry-run is clean, copy the skill to the VPS production gateway. Set dry_run: false only after a second dry-run on the VPS confirms everything.
Print this. Stick it on your wall. Follow it every time.
✅ Write prompt.md before index.js — always✅ Test with 10+ real sample inputs before shipping✅ Set dry_run: true until you've seen 3 clean dry-runs✅ Catch all errors and notify CORA✅ Use claude-haiku-4-5 as default model✅ Use draft_and_approve: true for all external comms✅ Keep config.json for business settings (thresholds, names, numbers)✅ Log what the skill did to memory after each run✅ One skill = one job, named after what it does
🚫 Never deploy directly to VPS without dry-run on MacBook Pro first🚫 Never use wildcard tools: ["*"] in skill.json🚫 Never trigger financial transactions — draft only🚫 Never hardcode API keys, tokens, or passwords in skill files🚫 Never use shell tool unless explicitly approved by Boss🚫 Never send external comms without draft_and_approve: true🚫 Never use Sonnet model without written approval🚫 Never combine two functions into one skill file🚫 Never fail silently — always catch and report to CORA
── OPS FLEET · VPS (Hostinger, Malaysia) · Managed by CORA ──────────────────CORACommand, Orchestration & Resource Administrator · COO · ✅ LIVEDeployment: VPS (Hostinger, Malaysia) · Tools: all ops agents, memory, reporting · always-onOversees: ARIA, MAX, SUQI, CRAIGARIAAutomated Response & Intelligence Assistant · Customer Service · ✅ ActiveTools: whatsapp, email, wmg-connect-api, memory · Reports to: CORAMAXMarketing Automation & eXecution · Marketing Manager · 🔜 Coming SoonTools: gmail, web_search, memory · Reports to: CORASUQIService & Quality Intelligence · Service Quality · 🔜 Coming SoonTools: memory, reporting, whatsapp · Reports to: CORACRAIGClient Relations & Account Intelligence Guide · CRM · 🔜 Coming SoonTools: gmail, whatsapp, crm, memory · Reports to: CORARITARemote IT & Technology Administrator · IT Ops · 🔜 Coming SoonTools: shell (approved), monitoring, memory · Reports to: CORA── BACK-OFFICE FLEET · MacMini Local · Managed by FORD · May 2026 ─FORDFiscal Oversight & Resource Deployment · CFO · 🔜 May 2026Deployment: MacMini (local, air-gapped) · Oversees: FINN, HERA, DEVIFINNFinancial Intelligence & Numerical Navigator · Finance · 🔜 Coming SoonTools: gmail, memory, reporting · Reports to: FORD · requires_approval: true ALWAYSHERAHuman Resources Engagement & Records Administrator · HR · 🔜 Coming SoonTools: gmail, memory, calendar · Reports to: FORD · requires_approval: trueDEVIDevelopment & Engineering Virtual Intelligence · Software Dev · 🔜 Coming SoonTools: shell (approved), github, memory · Reports to: FORDRITARemote IT & Technology Administrator · IT Ops · 🔜 Coming SoonTools: shell (approved), monitoring, memory · Reports to: FORD
# Skill folder naming conventionwmg-[agent]-[function]# Exampleswmg-aria-email-triage← ARIA, email triage functionwmg-aria-whatsapp-reply← ARIA, WhatsApp auto-replywmg-finn-invoice-monitor← FINN, invoice monitoringwmg-suqi-sla-alert← SUQI, SLA breach alertingwmg-cora-health-check← CORA, swarm health checkwmg-craig-crm-update← CRAIG, CRM record update# Function naming in index.js — verb-noun formatfetchUnreadEmails()classifyUrgency()sendWhatsAppAlert()updateMemory()notifyCORA()# Branch naming for skill developmentskill/wmg-aria-email-triageskill/wmg-finn-invoice-monitor