agentleFS
glodyfimpaglodyfimpa/claude-skills/portable-local-routine/SKILL.md

portable-local-routine

Skill0 starsChanged 31 days agoMITView on GitHub

Gate di portabilità per routine e agenti schedulati LOCALI (script che girano a orari fissi via launchd/cron, non nel cloud di Claude). Lo standard: una routine locale si costruisce portabile, gira via clone su QUALSIASI PC — il Mac oggi, una VPS Linux sempre accesa domani — senza riscrivere niente e senza dipendere dal cloud. Usa questa skill quando stai costruendo o modificando una routine/agente schedulato locale (modalità build, come gate prima di considerarlo finito) O quando vuoi controllare una routine esistente e conformarla allo standard (modalità audit). Include un gate a monte (Gate 0) che decide la FORMA giusta: routine locale launchd/cron, Claude routine dentro l'app (quando serve un MCP autenticato interattivamente nell'app), o ibrido — usalo anche quando ti chiedi "questa la faccio come scheduled-task Claude o come script launchd?" o "mi servono gli MCP per questa routine?". L'asse che decide il trigger è "schedulato o no": questa skill fira solo quando l'artefatto è una routine SCHEDULATA (launchd/cron/job a orari fissi); per la portabilità di SINTASSI di uno script bash qualsiasi non-schedulato delega a bash-portability-linter. Triggera su: "routine portabile", "questa routine schedulata gira su ogni PC", "che giri anche su VPS", "scheduling locale", "launchd", "cron job locale", "portable local routine", "controlla la portabilità di questa routine", "audit routine locale", "questa routine gira solo sul mio Mac?", "rendi portabile questo script schedulato". NON triggera per: routine cloud-native (Claude Code Routines/CCR), portabilità di sintassi di uno script non-schedulato (→ bash-portability-linter, bash 3.2/BSD), o CI/CD su runner cloud.

  • Reads credentials

The file

Files
SKILL.md

Portable Local Routine — gate di portabilità

Una "routine locale" è uno script (di solito bash + claude -p/CLI) che gira a orari fissi su un PC, lanciato da uno scheduler del sistema operativo (launchd su macOS, cron su Linux). A differenza di una Claude Code Routine cloud, non gira a PC spento — ma con un design portabile lo stesso clone può girare su un PC/VPS sempre acceso, risolvendo il caso "PC spento" per spostamento dell'hardware invece che per cambio di runtime.

Questa skill è il gate che garantisce quel design. Una routine costruita male è inchiodata a una macchina: path assoluti che esistono solo lì, scheduler scritto per un solo OS, segreti non clonabili, dipendenze implicite. Spostarla su un altro PC diventa una riscrittura. Il gate previene quel debito mentre il costo di evitarlo è ancora basso.

Gate 0 — è davvero il caso di una routine locale? (decidi PRIMA dei 7 criteri)

Prima di applicare i criteri di portabilità, decidi in quale forma va costruita la routine. Esistono tre forme, e si scelgono in base a UNA domanda: la routine ha bisogno di un MCP che è autenticato interattivamente dentro l'app Claude (Notion/Calendar/Gmail collegati cliccando in Claude Desktop, sessione OAuth viva nell'app)?

Non confondere "usa un MCP" con "usa un MCP dell'app". claude -p headless può caricare server MCP via --mcp-config se l'MCP è process-based e si avvia/autentica da solo. Il discriminante non è "MCP sì/no", è come è autenticato/avviato:

  • MCP stdio/process-based (un comando che claude -p può rilanciare: npx ..., docker ..., un binario; credenziali in env o file) → claude -p lo carica con --mcp-config e il tool risponde, anche su VPS. Conta come "solo-CLI" ai fini del gate.
  • MCP autenticato interattivamente nell'app (OAuth fatto nell'UI, sessione che vive nell'app) → un claude -p headless parte come processo nuovo, col proprio contesto MCP, e non riusa quella sessione: quell'MCP gli è assente. Non c'è un comando stdio da rilanciare via --mcp-config (la sua "config" è la sessione viva nell'app), quindi non lo recuperi headless.

Verificato 2026-06-26 (test diretto, non dedotto): claude -p headless nudo → NO_MCP (zero tool MCP; gli MCP dell'app NON sono ereditati). Lo stesso claude -p con --mcp-config su un server stdio process-based (sequential-thinking, npx) → il tool mcp__sequential-thinking__sequentialthinking è disponibile e risponde. Conferma la regola: process-based si ricarica headless, app-interattivo no. Per un caso dubbio il test è di 2 minuti: claude -p --mcp-config <file.json> -- 'hai il tool X? SI/NO'.

Le tre forme

A. Solo-CLI / MCP-headless-configurabile → routine locale launchd/cron (quella che questa skill standardizza). La routine fa lavoro da riga di comando (git, gh, curl, claude -p, test runner) ed eventuali MCP autenticabili da sé via --mcp-config. È la scelta strettamente migliore quando si applica: gira come processo del SO (non si interrompe se usi l'app, gira anche con l'app chiusa) ed è portabile su VPS. Procedi con i 7 criteri sotto.

B. Serve un MCP interattivo dell'app, e SOLO quello → Claude routine dentro l'app (scheduled-task in ~/.claude/scheduled-tasks/, non questa skill). Accetti i due limiti noti — si interrompe se l'app è occupata al fire ([reference] task local interrotto da sessione attiva), non gira su VPS — perché sono il prezzo per avere la sessione MCP viva. Questa skill non si applica: NON forzare la forma launchd su una routine che dipende da un MCP interattivo, la romperesti.

C. Misto: serve un MCP interattivo dell'app PER UNA PARTE, più lavoro CLI/git/PR per il resto → ibrido a due stadi. Lo stadio MCP gira dentro l'app (legge Notion/Calendar/Gmail) e passa i dati già estratti come argomenti a uno script portabile, che fa la parte CLI. Attenzione al falso ibrido: una routine-app che lancia uno script il quale richiama claude -p non trasferisce gli MCP dell'app al sotto-processo (claude -p riparte da zero). L'ibrido che regge è "l'app estrae → lo script elabora i dati estratti", non "l'app chiama un claude headless sperando che erediti gli MCP". Lo script della parte CLI va reso portabile coi 7 criteri sotto; lo stadio MCP-app resta dentro l'app.

Decisione (due assi)

Il primo asse è "serve un MCP interattivo dell'app?"; il secondo, che separa B da C, è "c'è lavoro CLI sostanziale (git/PR/test) oltre alla parte MCP?".

MCP interattivo dell'app?+ lavoro CLI sostanziale?Forma
No(qualunque)A — script launchd/cron (questa skill)
Sì, ed è tutto lìNoB — Claude scheduled-task dentro l'app
Sì, ma solo per una parteSìC — l'app estrae i dati → script portabile li elabora

"Lavoro CLI sostanziale" = abbastanza da giustificare uno script portabile a parte (aprire issue/PR, girare test, build). Una singola curl di notifica NON lo è: una routine che legge un MCP-app e manda un Telegram resta forma B, non diventa C per via del curl finale.

Se sei in forma A o nello stadio-script della forma C, prosegui coi 7 criteri. Se sei in forma B, questa skill non è quella giusta.

Quando usarla — due modalità

build — stai costruendo una routine nuova. Usa i 7 criteri sotto come checklist prima di considerarla finita. Idealmente trasformali in TODO così non ne salti uno.

audit — esiste già una routine e vuoi sapere se è portabile (o conformarla). Leggi gli script reali, applica i 7 criteri uno per uno, e produci il report sotto: cosa è conforme, cosa no, e come si sistema. In questa versione la skill consiglia, non modifica: i fix li applica chi guida la sessione, dopo aver visto il report.

I 7 criteri di portabilità

Per ciascuno: cosa controllare, perché conta, come si sistema.

1. Nessun path assoluto hard-coded

Cerca /Users/..., /home/..., /opt/homebrew, un $HOME letterale incollato, path che contengono uno username. Perché conta: su un altro PC quello username non esiste e lo script rompe al primo accesso. Fix: risolvi la radice dello script una volta sola con SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" e costruisci tutto relativo a quello. Per le directory utente usa le variabili d'ambiente ($HOME, ${XDG_CONFIG_HOME:-$HOME/.config}), non il path espanso.

2. Shebang ed esecuzione neutrali rispetto alla macchina

#!/usr/bin/env bash, non #!/bin/bash (su alcuni sistemi bash non è in /bin). Evita costrutti bash 4+ se il target può essere il bash 3.2 di macOS (per la sintassi fine c'è la skill bash-portability-linter). Perché conta: un'incompatibilità di shell si manifesta solo sull'altra macchina, dopo che pensavi fosse a posto.

3. Lo scheduler NON è OS-locked

Il pezzo che installa lo scheduling deve sapere girare su più OS. Un installer launchd-only non parte su una VPS Linux; un systemd-timer-only non parte sul Mac. Fix: un installer che rileva l'OS (uname -s) e installa il meccanismo nativo — launchd su macOS, cron su Linux — dietro un comando unico (./schedule.sh install). cron è il minimo comune denominatore (c'è ovunque); launchd in più dà su Mac il recupero dei fire persi durante lo sleep. In audit: uno scheduler launchd-only non è un difetto, è un gap di portabilità — la routine funziona oggi sul Mac, le manca solo il ramo cron per girare su una VPS. Marcalo [FIX] con "aggiungere il ramo cron", non come errore.

4. Segreti clonabili, mai versionati

Token e chiavi vivono in un file .env gitignored, accanto a un .env.example versionato che elenca le variabili senza i valori. Perché conta: così clonare è "copia .env.example → .env, compila, parti", e nessun segreto finisce nella storia git. Mai segreti hard-coded nello script né committati.

5. Dipendenze dichiarate + preflight + fail-fast

Elenca i binari che la routine invoca (jq, gh, git, curl, claude, python3, …). Una macchina fresca (VPS appena provisionata) potrebbe non averli. Fix: un preflight check all'avvio dell'installer che verifica ogni dipendenza e fallisce chiaro nominando cosa manca, invece di crashare a metà del primo fire con un errore oscuro. Correlato: set -euo pipefail in cima a ogni script. Senza set -e un comando fallito non ferma il run e la routine "fa finta di aver lavorato" — esattamente il fire-che-non-fa-nulla che il criterio 7 cerca di diagnosticare. È robustezza più che portabilità, ma è il prerequisito che rende affidabile il resto: una routine portabile ma che ingoia i propri errori è portabile e rotta su ogni macchina invece che su una sola.

macOS, repo sotto ~/Documents: plist con /bin/bash come primo argomento e log in ~/Library/Logs, altrimenti exit 78 silenzioso (TCC). Verifica: launchctl kickstart, poi "last exit code" ≠ 78.

Rete al primo fire: RunAtLoad (e il recupero di un fire perso nello sleep) parte al login o al risveglio, secondi prima che il DNS risponda. Una routine che usa la rete e non aspetta fallisce con "Could not resolve host" e resta rossa fino al fire successivo, che per una routine giornaliera è domani. Fix: prima del primo passo di rete, un'attesa limitata (poll curl -I su un host noto, timeout ~3 min); se resta offline, salta il fire con exit 0 e una riga di log, senza heartbeat: offline è l'ambiente, non un difetto della routine, e un blackout lungo emerge lo stesso come heartbeat mancante. I passi che non usano la rete (cancellazioni GDPR, pulizie locali) restano prima dell'attesa. In audit: una routine con RunAtLoad e chiamate di rete senza attesa è [FIX].

6. Niente dipendenza da bridge cloud quando il target è locale

Se la routine gira in locale, le notifiche e le API vanno chiamate dirette (curl a Telegram, gh diretto), non attraverso i bridge che servono solo in sandbox CCR (dove api.telegram.org è bloccato e gh non esiste). Perché conta: trascinarsi dietro l'impalcatura cloud in una routine locale aggiunge complessità e punti di rottura inutili. (Il bridge serve SOLO se il target è davvero CCR — allora è un'altra routine.)

7. Il fire è diagnosticabile da remoto

Devi poter sapere se un run schedulato è partito senza essere fisicamente al PC. Fix: un log strutturato (JSONL) che timestampa avvio ed esito di ogni fire. Così un fire saltato (PC spento all'orario) si legge come assenza di una riga attesa, distinto da un errore applicativo — e un errore applicativo la routine lo notifica da sé (Telegram/mail).

Formato del report (modalità audit)

Quando audìti una routine, produci questo, una riga per criterio:

Audit portabilità — <nome routine>

[OK]   1. Path assoluti        — nessuno, SCRIPT_DIR via BASH_SOURCE
[FIX]  2. Shebang              — run-x.sh riga 1: #!/bin/bash → #!/usr/bin/env bash
[FIX]  3. Scheduler OS-detect  — schedule.sh è launchd-only: aggiungere il ramo cron (uname=Linux)
[FIX]  4. Segreti clonabili    — .env gitignored OK, ma manca .env.example: crearlo con le chiavi senza valori
[OK]   5. Preflight + set -e   — preflight_check copre jq/gh/git/curl/claude; set -euo pipefail presente
[N/A]  6. Bridge cloud         — routine puramente locale, nessun bridge (corretto)
[OK]   7. Fire diagnosticabile — schedule.log JSONL fire_start/fire_end

Verdetto: 3 fix per la piena portabilità (criteri 2, 3, 4). Gli altri conformi.

Usa [OK] / [FIX] / [N/A]. Il tag è il verdetto del criterio; il testo della riga mette per ultima la cosa da fare (è il punchline azionabile). Per ogni [FIX] dai la riga/file/comando concreto da cambiare, mai un consiglio generico. Chiudi con un verdetto di una riga: quanti fix mancano e quali.

Fuori scope (dichiaralo se chiesto): questo gate copre la portabilità, non la correttezza a runtime. La sovrapposizione di run (un fire che parte mentre il precedente gira ancora) e i lock-file sono bug reali di routine schedulate, ma sono correttezza, non portabilità — non li controlla questa skill. Se emergono, segnalali a parte, non come [FIX].

Nota di evoluzione

Questa versione fa check + report. Quando il gate è collaudato, una modalità --fix potrà applicare i fix meccanici sicuri (shebang, path assoluto → SCRIPT_DIR) con test a guardia. Non è in questa versione: prima si valida il giudizio, poi si automatizza la mano.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.