Console
AI Ops Pack

automation-failure-triage

When a Hermes cron or webhook fails, read the relevant logs, identify the root cause, surface the fix, and optionally apply it to the cron config.

on-demand
bash
vault-sqlite-fts5
shipped

Name of the failed cron job, webhook, or skill — e.g. "daily-standup", "pipeline-health-report", or the skill file name

The error or failure signal you observed — paste the message, the Telegram alert, or describe what didn't happen that should have

Artifact will appear here

wiki/automation-fix-[slug].md

How this skill runs


# Automation Failure Triage

## When to run

The moment an automation fails — a cron that didn't send its Telegram message, a webhook that returned nothing, a skill that errored mid-run. Don't wait to triage this. Silent failures in automations compound: if the daily standup fails on Monday and you don't notice until Friday, you've lost a week of operating context.

The output of this skill is the root cause and the fix. In most cases the fix is one of four things: a broken MCP connection, an expired API key, a changed upstream schema, or a prompt that hit a model context limit. This skill finds which one it is.

## What you'll get

A triage report at `wiki/automation-fix-[slug].md` with the root cause identified, the specific fix documented, the steps you need to take (or that the agent will take if you authorize it), and a check that the automation runs clean after the fix. If the fix requires editing a skill file or cron config, the report includes the exact diff.

## Steps

1. Read the Hermes error log for recent failures: `bash -c "tail -200 ~/.hermes/logs/errors.log 2>/dev/null | grep -i 'error\|fail\|exception\|timeout' | tail -50"`. Parse for entries matching `automation_name`.

2. Read the Hermes agent log for the last run of this automation: `bash -c "grep -A 20 '[automation_name]' ~/.hermes/logs/agent.log 2>/dev/null | tail -80"`. Find the last run timestamp and the last line before failure.

3. Read the Hermes gateway log for API calls made during that run: `bash -c "grep -h '[timestamp]' ~/.hermes/logs/gateway.log 2>/dev/null | tail -50"` where `[timestamp]` is the approximate window of the failed run. Look for: HTTP error codes (401, 429, 500), timeout markers, connection refused errors.

4. Classify the failure type based on the log evidence:
   - **Auth failure (401/403):** An API key expired or was revoked. Identify which service.
   - **Rate limit (429):** Too many requests in the window. Identify which API and the limit.
   - **Model context exceeded:** Prompt + context exceeded model token limit. Identify the approximate token count.
   - **MCP server down:** A required MCP server isn't responding. Identify which one.
   - **Schema change:** An upstream API response changed format and the parsing broke. Identify the field.
   - **Cron config error:** The cron expression is malformed or the skill file path is wrong.
   - **Vault query failure:** SQLite FTS5 query returned an error or the vault.db is locked.
   - **Unknown:** Log evidence is insufficient — flag what additional data is needed.

5. Check the MCP server status if the failure type is or might be MCP-related: `bash -c "cat ~/.hermes/config.json 2>/dev/null | python3 -c 'import json,sys; d=json.load(sys.stdin); servers=d.get(\"mcpServers\",{}); [print(k, v.get(\"command\",\"N/A\")) for k,v in servers.items()]'"`. For each server the automation depends on, verify it can be invoked.

6. If the failure is auth-related, identify the credential source: `bash -c "grep -r '[service_name]' ~/.hermes/.env 2>/dev/null | head -5"` (redact the value in any output — show only the key name). Tell the user which key to rotate and where to set the new value.

7. If the failure is context-length-related, read the skill file to identify what context loading is happening: `bash -c "cat ~/.hermes/skills/[pack]/[skill-name].md 2>/dev/null | grep -A 5 'Step [0-9]'"`. Identify the step that loads the most tokens and suggest the reduction: FTS5 query returning too many results, full page loads instead of summaries, or a prompt prefix that grew too large.

8. Draft the fix. Be specific: the exact line to change, the exact new value, the exact command to run. Do not describe the fix in general terms — write it as a diff or a set of numbered shell commands.

9. Ask the user whether to apply the fix automatically or to present it for manual application. If automatic: apply the change, re-run the automation once manually to confirm it succeeds: `bash -c "hermes run [automation_name]"`. Capture the output and confirm it matches expected output format.

10. Write the triage report to `wiki/automation-fix-[slug].md`. Include: the failure log excerpt, the root cause classification, the fix applied, the confirmation run output, and any follow-up preventive measures (e.g. add a health check cron, add an alert if the cron doesn't produce output within 30 minutes of scheduled time).

## Output format

```yaml
---
type: wiki
title: "Automation Fix — [Automation Name]"
created: YYYY-MM-DD
updated: YYYY-MM-DD
status: resolved
tags: [caio, automation-fix, [automation-slug]]
sources: [hermes-logs, bash]
automation: "[automation_name]"
root_cause: "[failure-type]"
fix_applied: true|false
---
```

```markdown
# Automation Fix — [Automation Name]

> Triaged: YYYY-MM-DD HH:MM. Root cause: [failure type]. Fix: [applied / pending manual action].

## Failure Summary

- **Automation:** `[automation_name]`
- **Last successful run:** YYYY-MM-DD HH:MM
- **First observed failure:** YYYY-MM-DD HH:MM
- **Root cause:** [classification]

## Log Evidence

```
[Relevant log excerpt — error lines, last lines before failure]
```

## Root Cause

[2–3 sentences. What broke, why it broke, what triggered the break (key rotation, upstream change, etc.).]

## Fix

[Exact steps. Either applied already (say when) or presented for manual application.]

```diff
# If a file change:
- [old line]
+ [new line]
```

```bash
# If a shell action:
[exact command]
```

## Confirmation

[Output of the post-fix test run, or "pending — awaiting user confirmation to apply fix".]

## Prevention

- [Specific action to prevent this class of failure recurring]
```

## Example output (truncated)

```markdown
# Automation Fix — daily-standup

> Triaged: 2026-04-14 08:04. Root cause: Auth failure (Google Calendar MCP). Fix: pending manual action.

## Failure Summary

- **Automation:** `daily-standup`
- **Last successful run:** 2026-04-11 08:00
- **First observed failure:** 2026-04-14 08:00 (3 days silent)
- **Root cause:** Auth failure — Google OAuth token expired

## Log Evidence

```
2026-04-14 08:00:02 [gateway] ERROR: MCP google-calendar: 401 Unauthorized
2026-04-14 08:00:02 [gateway] Token refresh failed: invalid_grant
2026-04-14 08:00:03 [agent] skill daily-standup: dependency google-calendar-read failed — aborting run
```

## Root Cause

The Google Calendar MCP OAuth token expired after 7 days without a refresh. The Hermes MCP config is using a short-lived token rather than a refresh token flow. This will recur every 7 days until the auth flow is updated.

## Fix

1. Re-authorize the Google Calendar MCP: `hermes mcp reauth google-calendar`
2. Confirm the new token is written to `~/.hermes/config.json`
3. Update the MCP config to use offline access (refresh token): add `"access_type": "offline"` to the Google Calendar MCP auth block

## Prevention

- Add a daily health check cron that pings each MCP server and sends a Telegram alert if any return 401 or connection refused
```