name: hospital-devolucion-gmail-intake
description: Watches a Gmail inbox with gogcli for EPS→IPS glosa notifications, classifies emails as glosa batches, downloads Excel/CSV attachments, and creates a hospital_devolucion_batch task in Salmona with the file attached. Use it when the hospital wants to automatically process incoming glosas sent by an EPS via email, configure the devolucion watcher, or reprocess a glosa email that was missed.
version: 1.0.0
author: claudio@arkangel.ai
platforms: [macos, linux]
metadata:
hermes:
tags: [medical, hospital, glosa, devolucion, gmail, intake, colombia, ips]
category: medical-insurance-audit
requires_toolsets: [terminal]
required_environment_variables:
- name: GOGCLI_CREDENTIALS_PATH
prompt: Path to the gogcli OAuth credentials
help: Generate with
gogcli auth initusing a Google account with access to the hospital inbox. Same credentials as medical-invoice-gmail-intake if sharing a single inbox. required_for: full functionality - name: GMAIL_DEVOLUCION_LABEL prompt: Gmail label to watch for incoming glosas (e.g. "glosas" or "devolucion") help: Create a dedicated label in Gmail and configure a filter so EPS glosa emails land there. Avoid watching INBOX directly to prevent mixing with audit-side emails. required_for: full functionality
- name: SALMONA_API_URL prompt: Base URL of the Salmona API (e.g. https://salmona.arkangel.ai) required_for: full functionality
- name: SALMONA_API_KEY prompt: Salmona API key with agent role help: Generate via Salmona settings. Must have permission to create tasks at queued status. required_for: full functionality
hospital-devolucion-gmail-intake
First skill in the hospital devolucion pipeline. It listens on a Gmail label for incoming glosa notifications from EPSs, downloads the attached Excel or CSV files, and creates a hospital_devolucion_batch task in Salmona. The batch task then spawns one hospital_devolucion child task per glosa group for analysis by hospital-devolucion-audit.
Flow position: Gmail → this skill → hospital_devolucion_batch (Salmona) → hospital_devolucion × N → hospital-devolucion-audit
When to Use
- The IPS wants to start/configure the Gmail watcher for incoming glosas.
- A new email arrives in the
$GMAIL_DEVOLUCION_LABELlabel with an Excel attachment containing glosa line items and must be filed. - An email landed in
hospital-devolucion/errorand needs to be reprocessed manually. - The user asks "¿cómo entra una glosa de la EPS al sistema?" or "¿el correo de Sura ya fue procesado?".
Do not use: if the email has no Excel or CSV attachment; if it already has label hospital-devolucion/intake (avoid double processing); if the attachment looks like a regular invoice for EPS audit (use medical-invoice-gmail-intake instead).
Distinction from medical-invoice-gmail-intake: that skill handles invoices sent by IPS to EPS (aseguradora perspective). This skill handles glosas sent by EPS to IPS (hospital/prestador perspective). The email direction, task type, and context schema are completely different.
Input Contract
Trigger: Gmail message arrival on label $GMAIL_DEVOLUCION_LABEL
OR explicit call with a specific message_id for reprocessing
No structured JSON input required. The skill reads directly from Gmail using gogcli.
Output Contract
On success, the skill creates a hospital_devolucion_batch task in Salmona. The task carries:
- Context — batch metadata (see schema below).
- Input files — the Excel/CSV attachment uploaded to the task so the batch agent can read it.
Batch context schema:
| Field | Type | Description |
|---|---|---|
batch_id |
string | BATCH-YYYYMMDD-XXXXX generated by this skill |
documentos |
string[] | Names of all uploaded attachments |
pagador_nombre |
string | null | Payer name extracted from email or Excel; null if not found |
email_origen |
string | From address of the triggering email |
email_subject |
string | Subject line of the triggering email |
message_id |
string | Gmail message ID for traceability |
The skill returns:
{
"batch_task_id": "<salmona-task-id>",
"message_id": "<gmail-message-id>",
"label_aplicado": "hospital-devolucion/intake",
"archivos_radicados": [
{ "name": "glosas_mayo.xlsx", "sha256": "<hex>" }
],
"pagador_detectado": "EPS Sura"
}
On non-glosa emails: { "label_aplicado": "hospital-devolucion/not-applicable" } and stops.
On failure: { "label_aplicado": "hospital-devolucion/error", "motivo": "<string>" } and stops.
Procedure
Verify tools and credentials.
gogcli --version test -f "$GOGCLI_CREDENTIALS_PATH" || { echo "Missing gogcli creds"; exit 1; }Start the watcher (or process a specific message).
- Real-time push watcher:
gogcli watch start --label "$GMAIL_DEVOLUCION_LABEL" --topic hospital-devolucion-intake - Polling (fallback): list unprocessed messages.
gogcli messages list \ --label "$GMAIL_DEVOLUCION_LABEL" \ --query "-label:hospital-devolucion/intake -label:hospital-devolucion/not-applicable -label:hospital-devolucion/error has:attachment" - Reprocess a specific message:
gogcli messages get "$MESSAGE_ID" --format full
- Real-time push watcher:
Classify the email — is it a glosa batch?
Positive signals (at least 2 must match):
- Subject contains:
glosa,glosas,devolución técnica,devolucion tecnica,notificación glosa,respuesta glosa,objetación, or a glosa/document number pattern. - Sender domain matches a known EPS (sura.com.co, compensar.com, sanitas.com.co, famisanar.com, etc.).
- At least one attachment is an Excel (
.xlsx,.xls) or CSV whose filename or first-row headers suggest glosa data (columns likeCUPS,causal,valor_glosado,num_glosa,num_documento).
If it does not match → apply label
hospital-devolucion/not-applicableand stop:gogcli messages modify "$MESSAGE_ID" --add-label hospital-devolucion/not-applicable- Subject contains:
Check for duplicate (idempotency). Before creating a task, verify no
hospital_devolucion_batchtask already exists withcontext.message_id = "$MESSAGE_ID":curl -s -H "Authorization: Bearer $SALMONA_API_KEY" \ "$SALMONA_API_URL/api/tasks?task_type=hospital_devolucion_batch&limit=50" \ | jq --arg mid "$MESSAGE_ID" '.data[] | select(.context.message_id == $mid) | .id'If a task is found → apply label
hospital-devolucion/intake(if not already present) and stop.Download Excel/CSV attachments.
WORK_DIR="/tmp/devolucion-intake/$MESSAGE_ID" mkdir -p "$WORK_DIR" gogcli messages attachments download "$MESSAGE_ID" \ --filter "*.xlsx,*.xls,*.csv" \ --out "$WORK_DIR"If no Excel/CSV found → apply label
hospital-devolucion/errorwithmotivo: "no_excel_attachment"and stop.Extract payer name (best-effort). Try in order:
- First row/header of the Excel for a "pagador", "EPS", or "aseguradora" column.
- Sender display name or domain (map known EPS domains to nombres).
- Subject line keywords.
- If nothing found →
pagador_nombre: null(acceptable).
For each Excel/CSV attachment, create a Salmona batch task.
Generate a fresh
batch_idfor each file so each task is independently traceable:DATE=$(TZ=America/Bogota date +%Y%m%d) SUFFIX=$(tr -dc 'A-Z0-9' </dev/urandom | head -c 5) BATCH_ID="BATCH-${DATE}-${SUFFIX}"a. Set the batch description. Per issue
arkangelai/salmona-api#210, the skills repo is the canonical home for agent prompts. The task description is a thin pointer to the skill that processes the envelope (hospital-devolucion-batch-parse), not an inlined prompt:DESCRIPTION="Run skill hospital-devolucion-batch-parse on the attached Excel/CSV. Each row becomes one hospital_devolucion task (one glosa = one item)." DESCRIPTION_JSON=$(jq -n --arg d "$DESCRIPTION" '$d')b. Create the batch task (agent role allows
status: queueddirectly):PAYLOAD=$(jq -n \ --arg title "Lote glosas — ${PAGADOR_NOMBRE:-Email ${MESSAGE_ID}}" \ --argjson description "$DESCRIPTION_JSON" \ --arg batch_id "$BATCH_ID" \ --arg filename "$FILENAME" \ --argjson pagador_nombre "$PAGADOR_JSON" \ --arg email_origen "$FROM_ADDRESS" \ --arg email_subject "$SUBJECT" \ --arg message_id "$MESSAGE_ID" \ '{ title: $title, description: $description, task_type: "hospital_devolucion_batch", priority: "medium", context: { batch_id: $batch_id, documentos: [$filename], pagador_nombre: $pagador_nombre, email_origen: $email_origen, email_subject: $email_subject, message_id: $message_id } }') TASK=$(curl -s -X POST \ -H "Authorization: Bearer $SALMONA_API_KEY" \ -H "Content-Type: application/json" \ -d "$PAYLOAD" \ "$SALMONA_API_URL/api/tasks") TASK_ID=$(echo "$TASK" | jq -r '.data.id')c. Upload the Excel file as a task input:
curl -s -X POST \ -H "Authorization: Bearer $SALMONA_API_KEY" \ -F "file=@$WORK_DIR/$FILENAME" \ -F "description=$FILENAME" \ -F "local_path=/hospitales/devolucion/$BATCH_ID/$FILENAME" \ "$SALMONA_API_URL/api/tasks/$TASK_ID/inputs/upload"d. Queue the task:
curl -s -X PATCH \ -H "Authorization: Bearer $SALMONA_API_KEY" \ -H "Content-Type: application/json" \ -d '{"status": "queued"}' \ "$SALMONA_API_URL/api/tasks/$TASK_ID/status"Label the email and ACK.
gogcli messages modify "$MESSAGE_ID" \ --add-label hospital-devolucion/intake \ --add-label "hospital-devolucion/batch-$BATCH_ID" gogcli messages reply "$MESSAGE_ID" \ --body "ACK — Glosas recibidas y registradas. Lote: $BATCH_ID. task_id: $TASK_ID. Procesaremos y responderemos dentro del plazo."Clean up temp files.
rm -rf "$WORK_DIR"Return output payload.
{ "batch_task_id": "<task-id>", "message_id": "<gmail-message-id>", "label_aplicado": "hospital-devolucion/intake", "archivos_radicados": [ { "name": "glosas_mayo.xlsx", "sha256": "<hex>" } ], "pagador_detectado": "EPS Sura" }
Pitfalls
- Mixed inbox with
medical-invoice-gmail-intake: if both skills watch the same inbox, an EPS glosa email might match both classifiers. Use a dedicated$GMAIL_DEVOLUCION_LABEL(e.g. a Gmail filter that routes emails from known EPS domains with "glosa" in subject) to prevent overlap. - Excel with merged cells or multi-header rows: the batch agent handles this, but record the raw filename without trying to parse the Excel here — just download and upload it.
- Multiple Excel files in one email: create one batch task per file, each with its own
batch_id. The for-loop in step 8 handles this — do not merge attachments. - EPS sends a ZIP with the Excel inside: unzip first:
Then treat the extractedunzip -o "$WORK_DIR/$ZIP_FILE" -d "$WORK_DIR".xlsxas the attachment. gogclifails withinvalid_grant: OAuth token expired. Rungogcli auth refreshor regenerate withgogcli auth init.- Salmona returns 422
status must be queued: the API key does not have agent role. Verify the key was generated for the Salmona agent account (app_metadata.role = "agent"). - Duplicate on retry: the idempotency check in step 4 (filter by
context.message_id) prevents double-filing. Always run it before creating a task.
Verification
- After running the skill, the email has exactly one of the labels
hospital-devolucion/{intake|not-applicable|error}. - A
hospital_devolucion_batchtask exists in Salmona withcontext.message_idmatching the processed email. - The task has at least one input file (the Excel attachment).
- The task status is
queued. - The Gmail thread has an ACK reply containing the
batch_idandtask_id. - No duplicate batch task exists for the same
message_id.
References
../medical-invoice-gmail-intake/SKILL.md— equivalent intake skill for the EPS audit (aseguradora) side.../hospital-devolucion-audit/SKILL.md— the audit skill that processes each childhospital_devoluciontask.gogcli— internal Arkangel CLI for Gmail (see#ai-toolingon Slack).- Resolución 3047/2008 Anexo 6 — causales de glosa (1–7) y plazos de respuesta.