OpenClaw ha conquistato oltre 100.000 stelle su GitHub in meno di una settimana dal lancio, a gennaio 2026, diventando uno dei repository open-source in più rapida crescita della storia. Non si tratta di un semplice chatbot: è un agente AI personale che gira sul proprio hardware, agisce autonomamente e impara nuove abilità attraverso un sistema di skill modulari.
Questa guida copre tutto — dall'installazione alla configurazione avanzata — con tre esempi pratici di skill pronti all'uso, inclusa una che pubblica automaticamente articoli giornalistici su WordPress tramite WP-CLI.
Contenuto articolo
- 1. Cos'è OpenClaw e come funziona
- 2. Installazione
- 3. Configurazione
- 4. Il Sistema delle Skills
- 5. Automazione: Cron, Heartbeat e Webhook
- 6. Configurazione Multi-Agent
- 7. Esempi di impostazione Skills OpenClaw
- Skill 1 — Web Scraper e Digest Quotidiano delle News
- Skill 2 — Monitoraggio e Alert del Server
- Skill 3 — WordPress Remote News Publisher via SSH + WP-CLI
- Struttura della cartella
- SKILL.md
- config.json
- scripts/download_cover.py
- scripts/optimize_image.sh
- scripts/upload_media_remote.sh
- scripts/publish_wp_remote.sh
- Configurazione in ~/.openclaw/openclaw.json
- Iniezione chiave pubblica SSH nella skill
- Cron jobs per pubblicazione automatica
- Setup della chiave SSH (una-tantum)
- Requisiti sul server remoto
- Requisiti sulla macchina locale (OpenClaw)
- 8. Riferimento Comandi CLI {#cli}
- 9. Troubleshooting
- Risorse Utili
1. Cos'è OpenClaw e come funziona
OpenClaw (precedentemente noto come MoltBot e ClawdBot) è un framework open-source per agenti AI personali, progettato per girare direttamente sul proprio hardware. A differenza degli assistenti AI tradizionali, non si limita a rispondere a domande: agisce, esegue comandi, automatizza flussi di lavoro e impara nuove abilità in modo autonomo.
Creato da Peter Steinberger (fondatore di PSPDFKit), il progetto si basa su tre principi fondamentali:
- Local-first — tutti i dati, la memoria e le configurazioni risiedono sul proprio machine, senza dipendenza da servizi cloud.
- Model-agnostic — supporta Claude (Anthropic), GPT-4, Gemini, Llama e qualsiasi modello compatibile con l'API OpenAI.
- Community-extensible — le Skill sono file
SKILL.mdportabili, condivisibili e installabili dal marketplace ClawHub.
Il Loop dell'Agente
Quando si lancia openclaw gateway, si avvia un singolo processo Node.js che gestisce tutto: canali di messaggistica, sessioni, chiamate al modello, esecuzione degli strumenti e persistenza della memoria. Il ciclo agentico si compone di quattro fasi:
- Perceive — riceve un input (comando utente, evento cron, webhook, heartbeat).
- Plan — l'LLM analizza il contesto, la memoria e le skill disponibili.
- Act — esegue strumenti: shell, browser, web fetch, file system, API.
- Reflect — aggiorna la memoria, notifica l'utente e attende il prossimo ciclo.
Dove si posiziona rispetto ad altri strumenti
Gli LLM puri (ChatGPT, Claude) sono intelligenti ma non agiscono. Gli strumenti di automazione (n8n, Make, Zapier) agiscono ma richiedono configurazione esplicita. OpenClaw unisce entrambi: l'LLM decide cosa fare, il Gateway lo esegue.
2. Installazione
Requisiti di sistema
| Componente | Requisito |
|---|---|
| Node.js | ≥ 22.x (LTS raccomandato) |
| npm/pnpm | npm ≥ 10 o pnpm ≥ 9 |
| OS | macOS, Linux, Windows (WSL2) |
| RAM | Minimo 2 GB (4 GB+ raccomandati) |
| Disco | ~500 MB per l'installazione base |
Installazione via npm
npm install -g openclaw@latest
In alternativa con pnpm:
pnpm add -g openclaw@latest
Verifica l'installazione:
openclaw --version
Installazione via script (Linux/macOS)
curl -fsSL https://clawd.bot/install.sh | bash
⚠️ Sicurezza — Prima di eseguire script via
curl, esamina sempre il contenuto suclawd.bot. OpenClaw richiede permessi elevati sulla macchina.
Onboarding Wizard
Dopo l'installazione, avvia il wizard interattivo:
openclaw onboard --install-daemon
Il flag --install-daemon installa il daemon di sistema (launchd su macOS, systemd su Linux) in modo che il Gateway rimanga sempre attivo in background. Il wizard configura: modello LLM, canale di messaggistica, workspace principale e prime skill.
Verifica con Doctor
openclaw doctor
Controlla: stato del daemon, API key configurate, permessi del workspace, policy DM, presenza di binari richiesti dalle skill attive.
3. Configurazione
Il file principale: ~/.openclaw/openclaw.json
{
"agents": {
"defaults": {
"model": "claude-opus-4-6",
"provider": "anthropic",
"maxTokens": 8192
}
},
"gateway": {
"port": 18789,
"host": "127.0.0.1"
},
"skills": {
"load": {
"extraDirs": ["/path/to/custom/skills"]
}
}
}
Configurazione dei Modelli LLM
OpenClaw supporta qualsiasi provider compatibile OpenAI. I principali:
- Anthropic (Claude) — raccomandato per resistenza all'injection e long-context
- OpenAI (GPT-4, GPT-4o)
- Google (Gemini Flash, Gemini Pro)
- Provider locali via Ollama o LM Studio
Esempio configurazione Anthropic:
"providers": {
"anthropic": {
"apiKey": "sk-ant-...",
"defaultModel": "claude-opus-4-6"
}
}
Failover automatico tra modelli:
"modelFailover": [
"claude-opus-4-6",
"claude-sonnet-4-6",
"gpt-4o"
]
💡 Consiglio — Usa
claude-opus-4-6per task complessi (ragionamento, coding, analisi) e Gemini Flash per task semplici (riassunti, lookup veloci). Puoi cambiare modello dal menu Telegram in qualsiasi momento.
Configurazione dei Canali
Telegram — il canale più semplice per iniziare. Crea un bot con @BotFather e ottieni il token:
"channels": {
"telegram": {
"enabled": true,
"token": "YOUR_BOT_TOKEN",
"ownerIds": [123456789]
}
}
Slack — richiede una Slack App con permessi chat:write, im:read, im:write, users:read:
"slack": {
"enabled": true,
"botToken": "xoxb-...",
"signingSecret": "...",
"appToken": "xapp-..."
}
Il file soul.md
Uno degli aspetti più potenti di OpenClaw è il file soul.md — la personalità e le istruzioni permanenti dell'agente. Si trova nel workspace principale e viene caricato come system prompt persistente:
# Il mio Assistente AI Personale
## Personalità
Sei un assistente professionale, preciso e proattivo. Parli italiano.
Anticipi le esigenze e proponi soluzioni prima di essere interrogato.
## Contesto
- Nome: Marco
- Professione: Giornalista digitale
- Sito WordPress: https://miosito.it
- Server: VPS Ubuntu 22.04
## Regole operative
1. Prima di eseguire comandi distruttivi, chiedi conferma.
2. Logga sempre le azioni importanti in ~/logs/agent.log
3. Avvisami su Telegram se qualcosa va storto.
Sicurezza — Best Practice
- Non installare mai OpenClaw sull'account root di un server di produzione.
- Usa VM o container dedicati per ambienti ad alto rischio.
- Configura le Exec Approvals per i comandi shell pericolosi.
- Imposta spending cap sul dashboard del provider LLM.
- Esegui
openclaw doctorregolarmente.
⚠️ Attenzione — Un agente in loop può consumare molti token rapidamente. Imposta sempre un limite mensile di spesa prima di avviare automazioni autonome.
4. Il Sistema delle Skills
Cos'è una Skill
Una skill in OpenClaw è una cartella contenente un file SKILL.md con frontmatter YAML e istruzioni in linguaggio naturale. Le skill insegnano all'agente come usare strumenti specifici, seguire procedure particolari o automatizzare task ricorrenti.
my-skill/
SKILL.md # definizione principale
scripts/ # script Python/Bash
config.json # configurazione opzionale
Anatomia di un SKILL.md
---
name: nome-skill
description: Descrizione breve che appare nel prompt dell'agente
homepage: https://link-documentazione.com
user-invocable: true
disable-model-invocation: false
metadata:
{"openclaw": {
"emoji": "🔧",
"requires": {
"bins": ["wp", "python3"],
"env": ["WP_SSH_HOST"],
"config": ["browser.enabled"]
}
}}
---
# Istruzioni per l'agente
Qui vanno le istruzioni dettagliate in linguaggio naturale.
L'agente le leggerà e le seguirà per eseguire il task.
Posizioni e Precedenza
OpenClaw carica le skill da tre posizioni, in ordine di precedenza:
- Workspace skills —
<workspace>/skills→ priorità massima - Managed/local skills —
~/.openclaw/skills→ condivise tra tutti gli agenti - Bundled skills — incluse nell'installazione npm → priorità minima
ClawHub — Il Marketplace
ClawHub è il registry pubblico delle skill per OpenClaw. Comandi principali:
# Cerca una skill
clawhub search wordpress
# Installa una skill nel workspace
clawhub install wordpress-publisher
# Aggiorna tutte le skill installate
clawhub update --all
Gating (Filtri al Caricamento)
OpenClaw filtra le skill al caricamento in base ai requisiti dichiarati:
| Campo | Comportamento |
|---|---|
requires.bins |
I binari devono essere presenti nel PATH |
requires.env |
Le variabili d'ambiente devono esistere |
requires.config |
I path di openclaw.json devono avere valori truthy |
os |
La skill si carica solo sugli OS specificati |
Iniezione di Segreti nelle Skill
"skills": {
"entries": {
"my-wordpress-skill": {
"env": {
"WP_DB_PASS": "secret123",
"UNSPLASH_KEY": "your-api-key"
}
}
}
}
5. Automazione: Cron, Heartbeat e Webhook
Cron Jobs
"cron": {
"jobs": [
{
"id": "morning-briefing",
"schedule": "0 8 * * *",
"prompt": "Prepara il briefing mattutino: meteo, news, calendario.",
"channel": "telegram"
},
{
"id": "weekly-report",
"schedule": "0 9 * * 1",
"prompt": "Genera il report settimanale di analytics WordPress.",
"channel": "slack"
}
]
}
Heartbeat (Ciclo Autonomo)
"heartbeat": {
"enabled": true,
"intervalMinutes": 60,
"prompt": "Controlla se ci sono task pendenti, aggiorna la memoria, invia notifiche se necessario."
}
💡 Differenza chiave — Il Cron è per task schedulati a orari precisi. Il Heartbeat è per check periodici autonomi. In pratica: usa il Cron per "pubblica alle 9:00", usa il Heartbeat per "controlla ogni ora se c'è qualcosa da fare".
Webhook
"webhooks": {
"enabled": true,
"endpoints": [
{
"path": "/github-push",
"secret": "your-webhook-secret",
"prompt": "Un nuovo push su GitHub. Analizza le modifiche e aggiorna la documentazione."
}
]
}
6. Configurazione Multi-Agent
OpenClaw supporta più agenti sullo stesso Gateway, ognuno con il proprio workspace, soul.md, set di skill e canale dedicato. Architettura ideale per:
- Separare agenti per ruolo (sviluppo, marketing, giornalismo)
- Isolare gli ambienti per sicurezza (agente untrusted in sandbox Docker)
- Condividere skill comuni tra agenti diversi
Routing dei canali:
"routing": {
"telegram": {
"workBot": "agent-work",
"personalBot": "agent-personal"
}
}
7. Esempi di impostazione Skills OpenClaw
Skill 1 — Web Scraper e Digest Quotidiano delle News
Raccoglie automaticamente notizie da fonti RSS, le aggrega, applica un'analisi editoriale e invia un digest formattato su Telegram ogni mattina.
Struttura della cartella:
~/.openclaw/skills/news-digest/
SKILL.md
scripts/
fetch_rss.py
sources.json
SKILL.md:
---
name: news-digest
description: Raccoglie news da RSS, le aggrega e invia un digest quotidiano su Telegram
user-invocable: true
metadata:
{"openclaw": {
"emoji": "📰",
"requires": {
"bins": ["python3"],
"env": ["TELEGRAM_CHAT_ID"]
}
}}
---
# Skill: News Digest Quotidiano
## Trigger
Eseguita automaticamente alle 7:30 via cron job, oppure con /news-digest.
## Procedura
1. Esegui: python3 {baseDir}/scripts/fetch_rss.py > /tmp/raw_news.json
2. Per ogni notizia applica questa analisi:
- Valuta la rilevanza (1-10): impatto, novità, interesse
- Scrivi un riassunto di 2-3 righe in italiano
- Assegna categoria: Tecnologia, Economia, Politica, Scienza, Altro
3. Seleziona le TOP 5 notizie per rilevanza.
4. Formatta il digest:
🌅 *Buongiorno! Digest News — [DATA]*
📌 *[TITOLO]*
[RIASSUNTO]
🔗 [LINK]
5. Invia su Telegram. Logga in ~/openclaw-logs/news-digest-[DATA].json
scripts/fetch_rss.py:
#!/usr/bin/env python3
import json, feedparser
from datetime import datetime, timedelta
SOURCES = json.load(open('{baseDir}/sources.json'))
articles = []
for src in SOURCES['feeds']:
feed = feedparser.parse(src['url'])
for entry in feed.entries[:10]:
articles.append({
'title': entry.get('title', ''),
'summary': entry.get('summary', '')[:400],
'link': entry.get('link', ''),
'source': src['name']
})
print(json.dumps(articles, ensure_ascii=False))
sources.json:
{
"feeds": [
{"name": "Ansa", "url": "https://www.ansa.it/sito/notizie/tecnologia/tecnologia_rss.xml"},
{"name": "Wired IT", "url": "https://www.wired.it/feed/rss"},
{"name": "BBC Tech", "url": "https://feeds.bbci.co.uk/news/technology/rss.xml"}
]
}
Configurazione cron:
{
"cron": {
"jobs": [{
"id": "morning-news",
"schedule": "30 7 * * *",
"prompt": "Esegui la skill news-digest e invia il digest mattutino.",
"channel": "telegram"
}]
}
}
Skill 2 — Monitoraggio e Alert del Server
Monitora periodicamente CPU, RAM, disco e servizi critici di un server Linux, inviando alert proattivi con diagnosi e azioni consigliate su Telegram.
Struttura della cartella:
~/.openclaw/skills/server-monitor/
SKILL.md
scripts/
check_metrics.sh
thresholds.json
SKILL.md:
---
name: server-monitor
description: Monitora CPU, RAM, disco e servizi del server con alert intelligenti su Telegram
user-invocable: true
metadata:
{"openclaw": {
"emoji": "🖥️",
"requires": {
"bins": ["df", "free", "top", "systemctl", "python3"],
"env": ["ALERT_TELEGRAM_CHAT_ID"]
},
"os": ["linux"]
}}
---
# Skill: Server Monitor con Alert Intelligenti
## Esecuzione automatica
Gira ogni 15 minuti via heartbeat.
## Procedura
1. Raccogli metriche:
bash {baseDir}/scripts/check_metrics.sh > /tmp/metrics.txt
2. Confronta i valori con {baseDir}/thresholds.json
3. Determina la gravità:
- WARNING (🟡): metrica tra 70% e 85% della soglia critica
- CRITICAL (🔴): metrica sopra l'85%
4. Genera alert con:
- Metrica problematica e valore attuale
- Diagnosi probabile (es. "Possibile memory leak in nginx")
- Azioni consigliate (comandi specifici)
5. In caso di CRITICAL, esegui automaticamente:
sudo systemctl restart nginx (se nginx è coinvolto)
Notifica l'azione intrapresa.
scripts/check_metrics.sh:
#!/bin/bash
echo "=== CPU ==="
top -bn1 | grep 'Cpu(s)' | awk '{print $2}' | cut -d'%' -f1
echo "=== RAM ==="
free -m | awk 'NR==2{printf "%.1f\n", $3*100/$2}'
echo "=== DISCO ==="
df -h / | awk 'NR==2{print $5}' | tr -d '%'
echo "=== SERVIZI ==="
for svc in nginx mysql php8.2-fpm; do
systemctl is-active $svc 2>/dev/null && echo "$svc:OK" || echo "$svc:FAIL"
done
thresholds.json:
{
"cpu_warning": 70,
"cpu_critical": 90,
"ram_warning": 75,
"ram_critical": 90,
"disk_warning": 80,
"disk_critical": 95,
"services": ["nginx", "mysql", "php8.2-fpm"]
}
⚠️ Sicurezza — Configura
sudoersper permettere solo i comandi specifici necessari (es.systemctl restart nginx) senza password, e mai con accesso root completo.
Skill 3 — WordPress Remote News Publisher via SSH + WP-CLI
Versione remota della Skill 3 originale.
Rispetto alla versione locale, questa skill non richiede WP-CLI installato sulla macchina che esegue OpenClaw: tutta l'interazione con WordPress avviene sul server remoto tramite connessione SSH con autenticazione automatica a chiave pubblica. Le immagini vengono scaricate e ottimizzate localmente, trasferite sul server viascp, e poi importate conwp media importeseguito in remoto.
Struttura della cartella
~/.openclaw/skills/wp-remote-publisher/
SKILL.md
scripts/
download_cover.py
optimize_image.sh
upload_media_remote.sh
publish_wp_remote.sh
config.json
SKILL.md
---
name: wp-remote-publisher
description: Genera e pubblica automaticamente articoli di news su WordPress remoto
via SSH con autenticazione a chiave pubblica e WP-CLI installato sul server.
Scarica e ottimizza immagini di copertina da Unsplash, le trasferisce via scp
e pubblica con metadati SEO Yoast.
user-invocable: true
metadata:
{"openclaw": {
"emoji": "📝",
"requires": {
"bins": ["ssh", "scp", "python3", "curl", "convert"],
"env": [
"WP_SSH_HOST",
"WP_SSH_USER",
"WP_SSH_KEY",
"WP_REMOTE_PATH",
"UNSPLASH_ACCESS_KEY",
"WP_AUTHOR_ID"
]
}
}}
---
#### Skill: WordPress Remote News Publisher
#### IMPORTANTE — Filosofia Editoriale
Ogni articolo DEVE rispettare queste regole:
- Scrivi come un giornalista senior del settore, non come un AI.
- Usa frasi di lunghezza variabile. Alterna periodi brevi a costruzioni articolate.
- Inserisci una tesi editoriale chiara nel primo paragrafo (lede).
- Usa citazioni attribuite a fonti reali quando disponibili.
- EVITA: "è importante notare", "nell'era digitale", "nel mondo di oggi",
"in conclusione", "ovviamente", "chiaramente", qualsiasi formula AI.
- Il titolo deve essere specifico. Niente clickbait.
#### Variabili d'ambiente richieste
| Variabile | Descrizione | Esempio |
|---------------------|---------------------------------------------------------|--------------------------------------|
| WP_SSH_HOST | Hostname o IP del server remoto | `203.0.113.10` o `miosito.it` |
| WP_SSH_USER | Utente SSH sul server remoto | `ubuntu` / `www-data` / `deploy` |
| WP_SSH_KEY | Path assoluto alla chiave privata SSH locale | `/home/user/.ssh/id_ed25519_wp` |
| WP_SSH_PORT | Porta SSH (default 22) | `22` |
| WP_REMOTE_PATH | Path assoluto di WordPress sul server remoto | `/var/www/html/wordpress` |
| WP_REMOTE_TMP | Cartella temporanea scrivibile sul server remoto | `/tmp` |
| UNSPLASH_ACCESS_KEY | Access Key API Unsplash | `AbC123...` |
| WP_AUTHOR_ID | ID autore WordPress | `1` |
#### Trigger
Eseguita ogni giorno alle 10:00 e 16:00 (lun-ven) via cron job.
Invocabile manualmente con: /wp-remote-publisher [argomento]
---
#### Procedura Completa
#### FASE 1 — Selezione Argomento
Se non viene fornito un argomento:
1. Leggi {baseDir}/config.json per la lista di topic configurati.
2. Seleziona il topic con la pubblicazione più vecchia (round-robin).
#### FASE 2 — Verifica Connessione SSH
Prima di qualsiasi operazione, verifica che la connessione SSH funzioni:
ssh -i $WP_SSH_KEY -p ${WP_SSH_PORT:-22} -o StrictHostKeyChecking=no \
-o BatchMode=yes -o ConnectTimeout=10 \
$WP_SSH_USER@$WP_SSH_HOST \
"wp --info --path=$WP_REMOTE_PATH" 2>&1
Se il comando fallisce, interrompi e notifica l'errore su Telegram.
#### FASE 3 — Ricerca e Raccolta Fatti
1. Cerca via web: "[argomento] ultime notizie [mese corrente]"
Cerca anche in inglese per fonti internazionali.
2. Raccogli SOLO fatti verificabili:
- Dati numerici con fonte
- Dichiarazioni di persone reali con nome e ruolo
- Date ed eventi specifici
- Evita speculazioni non attribuite
3. Salva i fatti in /tmp/wp_facts.json
#### FASE 4 — Generazione Articolo con Stile Giornalistico
Struttura editoriale obbligatoria:
**TITOLO** (max 65 caratteri)
- Specifico, non generico. Contiene il fatto principale.
- Buono: "Meta taglia 3.600 posti: addio ai team AI di Base"
- Cattivo: "Meta compie un passo importante per il futuro"
**LEDE** (primo paragrafo, 40-60 parole)
- Risponde a: Chi? Cosa? Quando? Dove? Perché?
- È la notizia più importante in forma densa e precisa.
- Non inizia mai con "Nel mondo di..." o "Negli ultimi anni..."
**CORPO** (600-900 parole totali)
- Paragrafo 2: contesto e background
- Paragrafo 3-4: sviluppo principale con dati e citazioni
- Paragrafo 5: reazioni e posizioni dei protagonisti
- Paragrafo 6: implicazioni e prospettive (attribuite a esperti)
- Paragrafo finale: elemento che chiude il cerchio narrativo
**META DESCRIPTION** (max 155 caratteri)
**TAG SEO** (3-5 tag, senza #)
**KEYWORD PRINCIPALE** (1 keyword)
Salva in /tmp/wp_article.json:
{
"title": "...",
"content": "...",
"excerpt": "...",
"tags": ["..."],
"meta_desc": "...",
"keyword": "...",
"topic": "..."
}
#### FASE 5 — Immagine di Copertina
1. Determina una keyword visiva (es. "server room technology").
2. Scarica da Unsplash LOCALMENTE:
python3 {baseDir}/scripts/download_cover.py '[keyword]' /tmp/cover.jpg
3. Ottimizza localmente:
bash {baseDir}/scripts/optimize_image.sh /tmp/cover.jpg /tmp/cover_opt.jpg
4. Trasferisci sul server remoto e importa in WordPress:
bash {baseDir}/scripts/upload_media_remote.sh /tmp/cover_opt.jpg
→ ID salvato in /tmp/wp_media_id.txt
#### FASE 6 — Pubblicazione su WordPress Remoto
1. Esegui: bash {baseDir}/scripts/publish_wp_remote.sh
2. Post creato come draft. Aspetta 30 secondi, verifica lo stato via SSH.
3. Se OK, pubblica:
ssh -i $WP_SSH_KEY -p ${WP_SSH_PORT:-22} $WP_SSH_USER@$WP_SSH_HOST \
"wp post update $(cat /tmp/wp_post_id.txt) \
--post_status=publish --path=$WP_REMOTE_PATH"
4. Recupera l'URL del post pubblicato:
ssh -i $WP_SSH_KEY -p ${WP_SSH_PORT:-22} $WP_SSH_USER@$WP_SSH_HOST \
"wp post get $(cat /tmp/wp_post_id.txt) --field=url --path=$WP_REMOTE_PATH"
5. Invia conferma su Telegram con titolo, URL, parole, keyword.
#### FASE 7 — Aggiornamento Registro
Aggiorna {baseDir}/config.json segnando il topic come
"ultimo pubblicato" con timestamp per garantire la rotazione.
config.json
{
"wp_remote_path": "/var/www/html/wordpress",
"author_id": 1,
"categories": {
"tecnologia": 5,
"economia": 8,
"startup": 12
},
"topics": [
{
"name": "Intelligenza Artificiale",
"keywords": ["AI", "machine learning", "LLM"],
"category": "tecnologia",
"last_published": null
},
{
"name": "Cybersecurity",
"keywords": ["sicurezza informatica", "hacking", "privacy"],
"category": "tecnologia",
"last_published": null
},
{
"name": "Startup Tech",
"keywords": ["startup", "venture capital", "unicorn"],
"category": "startup",
"last_published": null
}
]
}
scripts/download_cover.py
Identico alla versione locale: scarica l'immagine da Unsplash sulla macchina locale.
#!/usr/bin/env python3
import sys, requests, os
query = sys.argv[1]
outfile = sys.argv[2]
api_key = os.environ['UNSPLASH_ACCESS_KEY']
r = requests.get(
'https://api.unsplash.com/photos/random',
params={'query': query, 'orientation': 'landscape', 'content_filter': 'high'},
headers={'Authorization': f'Client-ID {api_key}'}
)
r.raise_for_status()
data = r.json()
img_data = requests.get(data['urls']['regular']).content
with open(outfile, 'wb') as f:
f.write(img_data)
with open('/tmp/cover_meta.txt', 'w') as f:
f.write(f"Photo by {data['user']['name']} on Unsplash")
print(f"Immagine scaricata: {outfile}")
scripts/optimize_image.sh
Identico alla versione locale: ottimizza e ritaglia l'immagine sulla macchina locale con ImageMagick.
#!/bin/bash
INPUT=$1
OUTPUT=$2
# Resize a 1200x630 (dimensione Open Graph ottimale) e comprimi
convert "$INPUT" \
-resize 1200x630^ \
-gravity Center \
-extent 1200x630 \
-quality 85 \
-strip \
"$OUTPUT"
echo "Ottimizzazione completata: $(du -h "$OUTPUT" | cut -f1)"
scripts/upload_media_remote.sh
Questo script è la principale differenza rispetto alla versione locale.
Trasferisce l'immagine ottimizzata sul server remoto via scp, poi esegue wp media import tramite ssh.
#!/bin/bash
# ============================================================
# upload_media_remote.sh
# Trasferisce l'immagine sul server remoto e la importa
# in WordPress con WP-CLI remoto via SSH a chiave pubblica.
# ============================================================
IMAGE_PATH=$1
# --- Parametri SSH da variabili d'ambiente ---
SSH_HOST="${WP_SSH_HOST}"
SSH_USER="${WP_SSH_USER}"
SSH_KEY="${WP_SSH_KEY}"
SSH_PORT="${WP_SSH_PORT:-22}"
REMOTE_PATH="${WP_REMOTE_PATH:-/var/www/html/wordpress}"
REMOTE_TMP="${WP_REMOTE_TMP:-/tmp}"
# Opzioni SSH comuni (chiave pubblica, no password, no prompt)
SSH_OPTS="-i $SSH_KEY -p $SSH_PORT \
-o StrictHostKeyChecking=no \
-o BatchMode=yes \
-o ConnectTimeout=15 \
-o PasswordAuthentication=no"
# --- Validazione variabili ---
if [ -z "$SSH_HOST" ] || [ -z "$SSH_USER" ] || [ -z "$SSH_KEY" ]; then
echo "ERRORE: WP_SSH_HOST, WP_SSH_USER e WP_SSH_KEY sono obbligatori." >&2
exit 1
fi
if [ ! -f "$SSH_KEY" ]; then
echo "ERRORE: chiave SSH non trovata in $SSH_KEY" >&2
exit 1
fi
if [ ! -f "$IMAGE_PATH" ]; then
echo "ERRORE: immagine non trovata in $IMAGE_PATH" >&2
exit 1
fi
REMOTE_FILENAME="wp_cover_$(date +%s).jpg"
REMOTE_FILE_PATH="$REMOTE_TMP/$REMOTE_FILENAME"
# --- Trasferimento immagine via scp ---
echo "Trasferimento immagine su $SSH_USER@$SSH_HOST:$REMOTE_FILE_PATH ..."
scp $SSH_OPTS "$IMAGE_PATH" "$SSH_USER@$SSH_HOST:$REMOTE_FILE_PATH"
if [ $? -ne 0 ]; then
echo "ERRORE: scp fallito durante il trasferimento dell'immagine." >&2
exit 1
fi
echo "Immagine trasferita con successo."
# --- Importazione media con WP-CLI remoto ---
echo "Importazione media in WordPress via WP-CLI remoto..."
MEDIA_ID=$(ssh $SSH_OPTS "$SSH_USER@$SSH_HOST" \
"wp media import '$REMOTE_FILE_PATH' \
--path='$REMOTE_PATH' \
--porcelain 2>/dev/null")
if [ -z "$MEDIA_ID" ]; then
echo "ERRORE: wp media import non ha restituito un ID." >&2
# Cleanup file remoto anche in caso di errore
ssh $SSH_OPTS "$SSH_USER@$SSH_HOST" "rm -f '$REMOTE_FILE_PATH'" 2>/dev/null
exit 1
fi
# --- Cleanup file temporaneo remoto ---
ssh $SSH_OPTS "$SSH_USER@$SSH_HOST" "rm -f '$REMOTE_FILE_PATH'" 2>/dev/null
echo "$MEDIA_ID" > /tmp/wp_media_id.txt
echo "Media importato su WordPress con ID: $MEDIA_ID"
scripts/publish_wp_remote.sh
Esegue tutti i comandi wp sul server remoto tramite SSH. Nessuna chiamata WP-CLI locale.
#!/bin/bash
# ============================================================
# publish_wp_remote.sh
# Crea il post WordPress come draft via WP-CLI remoto (SSH).
# ============================================================
# --- Parametri SSH da variabili d'ambiente ---
SSH_HOST="${WP_SSH_HOST}"
SSH_USER="${WP_SSH_USER}"
SSH_KEY="${WP_SSH_KEY}"
SSH_PORT="${WP_SSH_PORT:-22}"
REMOTE_PATH="${WP_REMOTE_PATH:-/var/www/html/wordpress}"
AUTHOR_ID="${WP_AUTHOR_ID:-1}"
SSH_OPTS="-i $SSH_KEY -p $SSH_PORT \
-o StrictHostKeyChecking=no \
-o BatchMode=yes \
-o ConnectTimeout=15 \
-o PasswordAuthentication=no"
# --- Leggi dati articolo ---
TITLE=$(python3 -c "import json; d=json.load(open('/tmp/wp_article.json')); print(d['title'])")
CONTENT=$(python3 -c "import json; d=json.load(open('/tmp/wp_article.json')); print(d['content'])")
EXCERPT=$(python3 -c "import json; d=json.load(open('/tmp/wp_article.json')); print(d['excerpt'])")
TAGS=$(python3 -c "import json; d=json.load(open('/tmp/wp_article.json')); print(','.join(d['tags']))")
META_DESC=$(python3 -c "import json; d=json.load(open('/tmp/wp_article.json')); print(d['meta_desc'])")
KEYWORD=$(python3 -c "import json; d=json.load(open('/tmp/wp_article.json')); print(d['keyword'])")
MEDIA_ID=$(cat /tmp/wp_media_id.txt)
# --- Trasferisci il JSON dell'articolo sul server remoto (necessario per content lungo) ---
REMOTE_ARTICLE_JSON="/tmp/wp_article_remote_$(date +%s).json"
scp $SSH_OPTS /tmp/wp_article.json "$SSH_USER@$SSH_HOST:$REMOTE_ARTICLE_JSON"
# --- Crea il post come draft (WP-CLI remoto) ---
echo "Creazione post come draft su WordPress remoto..."
POST_ID=$(ssh $SSH_OPTS "$SSH_USER@$SSH_HOST" bash <<ENDSSH
TITLE=\$(python3 -c "import json; d=json.load(open('$REMOTE_ARTICLE_JSON')); print(d['title'])")
CONTENT=\$(python3 -c "import json; d=json.load(open('$REMOTE_ARTICLE_JSON')); print(d['content'])")
EXCERPT=\$(python3 -c "import json; d=json.load(open('$REMOTE_ARTICLE_JSON')); print(d['excerpt'])")
wp post create \
--post_title="\$TITLE" \
--post_content="\$CONTENT" \
--post_excerpt="\$EXCERPT" \
--post_status=draft \
--post_author=$AUTHOR_ID \
--post_type=post \
--path="$REMOTE_PATH" \
--porcelain 2>/dev/null
ENDSSH
)
if [ -z "$POST_ID" ]; then
echo "ERRORE: wp post create non ha restituito un ID." >&2
ssh $SSH_OPTS "$SSH_USER@$SSH_HOST" "rm -f '$REMOTE_ARTICLE_JSON'" 2>/dev/null
exit 1
fi
echo "Post draft creato con ID: $POST_ID"
# --- Imposta immagine di copertina ---
echo "Impostazione immagine di copertina..."
ssh $SSH_OPTS "$SSH_USER@$SSH_HOST" \
"wp post meta update $POST_ID _thumbnail_id $MEDIA_ID \
--path='$REMOTE_PATH'" 2>/dev/null
# --- Aggiungi tag ---
echo "Aggiunta tag..."
ssh $SSH_OPTS "$SSH_USER@$SSH_HOST" \
"wp post term add $POST_ID post_tag '$TAGS' \
--path='$REMOTE_PATH'" 2>/dev/null
# --- Meta SEO Yoast ---
echo "Aggiornamento meta SEO Yoast..."
ssh $SSH_OPTS "$SSH_USER@$SSH_HOST" \
"wp post meta update $POST_ID _yoast_wpseo_metadesc '$META_DESC' \
--path='$REMOTE_PATH'" 2>/dev/null
ssh $SSH_OPTS "$SSH_USER@$SSH_HOST" \
"wp post meta update $POST_ID _yoast_wpseo_focuskw '$KEYWORD' \
--path='$REMOTE_PATH'" 2>/dev/null
# --- Cleanup file temporanei remoti ---
ssh $SSH_OPTS "$SSH_USER@$SSH_HOST" "rm -f '$REMOTE_ARTICLE_JSON'" 2>/dev/null
echo "$POST_ID" > /tmp/wp_post_id.txt
echo "Post WordPress creato come draft con ID: $POST_ID"
Configurazione in ~/.openclaw/openclaw.json
Iniezione chiave pubblica SSH nella skill
"skills": {
"entries": {
"wp-remote-publisher": {
"env": {
"WP_SSH_HOST": "203.0.113.10",
"WP_SSH_USER": "deploy",
"WP_SSH_KEY": "/home/user/.ssh/id_ed25519_wp",
"WP_SSH_PORT": "22",
"WP_REMOTE_PATH": "/var/www/html/wordpress",
"WP_REMOTE_TMP": "/tmp",
"WP_AUTHOR_ID": "1",
"UNSPLASH_ACCESS_KEY": "la-tua-access-key-unsplash"
}
}
}
}
Cron jobs per pubblicazione automatica
"cron": {
"jobs": [
{
"id": "wp-morning-news",
"schedule": "0 10 * * 1-5",
"prompt": "Esegui la skill wp-remote-publisher. Scegli il topic dalla rotazione.",
"channel": "telegram"
},
{
"id": "wp-afternoon-news",
"schedule": "0 16 * * 1-5",
"prompt": "Esegui la skill wp-remote-publisher per il pomeriggio.",
"channel": "telegram"
}
]
}
Setup della chiave SSH (una-tantum)
Prima di usare la skill, configura l'autenticazione a chiave pubblica sul server remoto:
# 1. Genera una coppia di chiavi dedicata (raccomandato: ed25519)
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_wp -C "openclaw-wp-publisher" -N ""
# 2. Copia la chiave pubblica sul server remoto
ssh-copy-id -i ~/.ssh/id_ed25519_wp.pub -p 22 [email protected]
# 3. Verifica la connessione automatica (nessuna password richiesta)
ssh -i ~/.ssh/id_ed25519_wp -o BatchMode=yes [email protected] "wp --info"
# 4. (Opzionale) Limita ulteriormente la chiave in ~/.ssh/authorized_keys sul server
# Aggiungi prima della chiave: command="wp --allow-root",no-port-forwarding,no-X11-forwarding
💡 Consiglio sicurezza — Usa un utente SSH dedicato (
deployowpcli) con permessi minimi sul server. Non usareroot. Se WP-CLI richiede permessi su/var/www, aggiungi l'utente al gruppowww-data.
Requisiti sul server remoto
| Componente | Requisito | Verifica |
|---|---|---|
| WP-CLI | Installato e nel PATH | wp --info |
| PHP | ≥ 7.4 (8.x raccomandato) | php --version |
| Python 3 | Per leggere JSON nell'articolo | python3 --version |
| Permessi | Utente SSH scrive in WP_REMOTE_PATH |
ls -la /var/www/html/wordpress |
| Porta SSH | Aperta nel firewall | ufw status / iptables -L |
Requisiti sulla macchina locale (OpenClaw)
| Componente | Requisito | Installazione |
|---|---|---|
| ssh, scp | Presenti nel PATH | Pre-installati su Linux/macOS |
| ImageMagick | Comando convert |
apt install imagemagick |
| Python 3 | Con libreria requests |
pip install requests |
✅ In sintesi rispetto alla versione locale: WP-CLI non è più richiesto sulla macchina con OpenClaw. Tutti i comandi
wpvengono eseguiti viassh -i chiave ...sul server remoto. Le immagini vengono elaborate localmente e trasferite conscp. La connessione non richiede mai password grazie all'autenticazione a chiave pubblica.
Esempio di articolo generato con stile giornalistico:
Titolo: OpenAI apre i modelli o1 agli sviluppatori: tariffe ridotte del 40% e nuovi limiti di contesto
Lede: OpenAI ha reso disponibili via API i modelli della famiglia o1, finora riservati agli utenti ChatGPT Plus, con una riduzione dei costi del 40% rispetto all'anteprima pubblica. La mossa, annunciata il 20 febbraio, amplia la finestra di contesto a un milione di token per i tier enterprise e segnala un cambio di strategia nella monetizzazione dell'AI per sviluppatori.
Notare: nessun "nell'era digitale", nessun "è importante notare". Il lede risponde subito alle 5W con dati numerici precisi e fonte esplicita. Tono da agenzia stampa, non da blog.
8. Riferimento Comandi CLI {#cli}
| Comando | Descrizione |
|---|---|
openclaw onboard |
Avvia il wizard di configurazione guidata |
openclaw gateway |
Avvia il Gateway (processo principale) |
openclaw gateway --daemon |
Avvia il Gateway in background |
openclaw status |
Stato del Gateway e degli agenti |
openclaw stop |
Ferma il Gateway |
openclaw doctor |
Diagnosi configurazione e sicurezza |
openclaw logs |
Log del Gateway in tempo reale |
clawhub install <slug> |
Installa una skill da ClawHub |
clawhub search <query> |
Cerca skill nel registry |
clawhub update --all |
Aggiorna tutte le skill installate |
openclaw agent list |
Lista degli agenti configurati |
openclaw session list |
Lista delle sessioni attive |
9. Troubleshooting
Il Gateway non si avvia
Verifica che Node.js sia ≥22: node --version. Controlla i log con openclaw logs. Assicurati che la porta 18789 non sia occupata: lsof -i :18789.
Le skill non vengono caricate
Esegui openclaw doctor per rilevare binari mancanti o env non configurate. Controlla che SKILL.md abbia frontmatter YAML valido. Verifica che requires.bins siano nel PATH dell'utente che esegue OpenClaw.
WP-CLI restituisce errore di permessi
Usa l'utente web corretto (es. www-data) o il flag --allow-root solo in ambienti controllati. Verifica il path: wp --path=/var/www/html/wordpress post list.
Consumo eccessivo di token
Imposta spending cap sul dashboard del provider. Usa modelli economici (Gemini Flash) per skill semplici. Disabilita il heartbeat in sviluppo. Controlla che non ci siano loop nei cron job.
L'agente non trova le skill nel prompt
OpenClaw fa uno snapshot delle skill all'avvio della sessione. Dopo aver aggiunto una skill, riavvia la sessione o abilita skills.watcher per il hot-reload automatico.
Risorse Utili
- GitHub — github.com/openclaw/openclaw
- Documentazione — docs.openclaw.ai
- ClawHub — clawhub.com
- WP-CLI — wp-cli.org
- Unsplash API — unsplash.com/developers
- AgentSkills spec — agentskills.io
Hai domande o vuoi condividere la tua skill? Lascia un commento qui sotto o apri una issue su GitHub.




Lascia un commento