API management tool for status checking and troubleshooting Linux-hosted services.

Install

mkdir -p .claude/skills/api-ops && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/17389" && unzip -o skill.zip -d .claude/skills/api-ops && rm skill.zip

Installs to .claude/skills/api-ops

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Operate and troubleshoot the Patcher API service (`api/patcher_api/`) on its Linux host. Two modes: 1. STATUS SWEEP (`/api-ops`, `/api-status`, "check the api", "is the api healthy", "run a health check") — a read-only pass over the systemd units, cloudflared tunnel, app endpoints, database, disk, and the Healthchecks.io monitors, reporting green/yellow/red per component. 2. TROUBLESHOOTING (a symptom like "502 through cloudflared" / "service won't start", or pasted logs) — walks the known failure modes (KEYRING_BACKEND, cloudflared outbound-only, SQLite locking, systemd perms, deploy-token gating, restart loops, ingest failures). Also helps translate the systemd gotchas to a user's own Docker setup on a best-effort basis (Docker is not officially supported). Invoke on: "/api-ops", "/api-status", "patcher api won't start", "502 from cloudflared", "keyring error on linux", "is the api healthy", "why is patcher-deploy down", "schema-audit keeps flapping", or a pasted systemd / cloudflared / uvicorn log.
1016 charsno explicit “when” triggerlonger than Claude Code's old 250-char listing cap (fine on current versions)
Intermediate

Key capabilities

  • Perform a read-only status sweep of systemd units
  • Check cloudflared tunnel status
  • Verify app endpoints and database health
  • Inspect disk usage and Healthchecks.io monitors
  • Troubleshoot common failure modes like SQLite locking
  • Translate systemd gotchas to Docker setups

How it works

The skill operates in two modes: a status sweep that performs read-only checks on system components and a troubleshooting mode that diagnoses symptoms based on known failure modes and logs.

Inputs & outputs

You give it
Symptom description or pasted systemd/cloudflared/uvicorn log
You get back
Per-component verdict of system health or troubleshooting steps for a specific symptom

When to use api-ops

  • Run API health check
  • Troubleshoot service failure
  • Check system logs

About this skill

api-ops

Patcher's API service (api/patcher_api/) is the only piece intended to run on a Linux host. The documented deploy is uvicorn under systemd, fronted by a cloudflared tunnel. No inbound ports beyond 22/80/443 are opened. SQLite + SQLAlchemy 2.0 async is the backing store. /apps* and /stats are public; /admin/* is gated by a deploy token.

This skill has two modes: a proactive status sweep and reactive troubleshooting. A sweep that finds a problem flows straight into the matching troubleshooting gotcha below.

Everything here is read-only. Report findings and recommend fixes; let the user run anything that changes state (including Healthchecks.io dashboard edits).

Host layout (the map)

ThingPath / name
Code checkout (owner: the deploy code user)/opt/patcher
Virtualenv/opt/patcher/.venv
SQLite DB (owner: patcher)/var/lib/patcher-api/patcher_api.db
Service env file/etc/patcher-api/env
Deploy sentinel (touched by /admin/deploy)/var/lib/patcher-api/deploy-requested
API servicepatcher-api.service (box-only, not in repo)
Tunnelcloudflared.service

The patcher-api.service unit lives only on the box. Discover its port, user, and ExecStart at runtime (systemctl cat patcher-api.service) rather than assuming, the app binds a localhost port that cloudflared fronts.


Mode A: status sweep

Run these read-only checks in order and report a per-component verdict. Don't stop at the first yellow, complete the sweep so the summary is whole.

Run the checks sequentially, and append || true to any check whose non-zero exit is benign, notably systemctl is-failed, which exits non-zero precisely when a unit is healthy. One un-guarded non-zero exit can cancel a parallel command batch and abort the sweep mid-run.

Privileges (no passwordless sudo assumed)

This sweep runs unprivileged and must never invoke sudo or hang on a password prompt. systemctl reads, curl to localhost, and df need no privilege. Two capabilities unlock the rest:

  • Journal reads (journalctl -u ...) require the invoking user to be in the systemd-journal group. Grant once: sudo usermod -aG systemd-journal <user>, then re-login. Without it, journalctl for a unit returns nothing or permission errors.
  • DB-file inspection (step 7) needs read/traverse on /var/lib/patcher-api (owned by patcher). Add the user to the patcher group, or skip the raw file check and lean on /stats for freshness.

If a check needs elevation the sweep user doesn't have, do not run sudo. Print the exact sudo ... command for the human, mark that line "needs elevation" in the summary, and continue the rest of the sweep.

1. Discover the running config

systemctl cat patcher-api.service | grep -iE 'ExecStart|User|Environment'

Note the bind port (feeds the endpoint checks) and the service user.

2. Core service health

systemctl is-active patcher-api.service cloudflared.service
systemctl show patcher-api.service -p NRestarts -p ActiveEnterTimestamp
journalctl -u patcher-api.service -p warning --since "6 hours ago" --no-pager
  • active for both → green.
  • A climbing NRestarts or a recent restart cluster → possible restart loop (see G6).
  • Warnings/errors in the journal → pattern-match against the gotchas below.

3. Timers (scheduled jobs)

systemctl list-timers 'patcher-*' --no-pager
# `is-failed` has INVERTED exit codes: non-zero when HEALTHY (a oneshot at rest
# reads "inactive"). Guard with `|| true` or it cancels a parallel batch.
systemctl is-failed patcher-catalog-refresh.service patcher-schema-audit.service || true

Confirm patcher-catalog-refresh.timer and patcher-schema-audit.timer are active with a sane NEXT. A oneshot reading inactive/dead at rest is normal; only a literal failed is a problem. Then check each last run:

journalctl -u patcher-catalog-refresh.service -n 15 --no-pager
journalctl -u patcher-schema-audit.service -n 15 --no-pager
  • Catalog refresh should end with a Stitch summary: ... failed=0.
  • Schema audit should log Schema audit clean: live database matches the models. A non-zero exit means schema drift, investigate against the ORM models before the next deploy.

4. Deploy path unit

systemctl is-active patcher-deploy.path
journalctl -u patcher-deploy.service -n 20 --no-pager

The .path unit should be active (watching the sentinel). A stale "last deploy" here is NORMAL — deploys are event-driven, see the monitoring notes below. Only a /fail (non-zero deploy) is a real problem.

5. cloudflared tunnel

systemctl status cloudflared.service --no-pager | head -20

Tunnel should be connected. If the public URL 502s but the app answers on localhost, that's G2, not a real outage.

6. App endpoints (use the discovered port; default 8000)

PORT=8000   # replace with the discovered bind port
curl -fsS "http://127.0.0.1:${PORT}/health"
curl -fsS "http://127.0.0.1:${PORT}/stats"
curl -fsS "http://127.0.0.1:${PORT}/apps" | head -c 200
  • /health should return OK.
  • /stats carries last_refresh (ingest freshness). If last_refresh is older than ~26h, the daily catalog refresh has been missing — the same threshold the external Lambda monitor alerts on. Cross-check step 3.
  • /apps returning [] with no errors → G7 (empty catalog / ingest never populated).

7. Database + disk

df -h /var/lib/patcher-api /opt/patcher                # no privilege needed
stat -c '%U:%G' /var/lib/patcher-api/patcher_api.db    # needs read on the dir
  • df always works. The stat needs read/traverse on /var/lib/patcher-api (owned by patcher); if the sweep user isn't in the patcher group, skip it and note "DB file check needs elevation" rather than sudo-prompting. Freshness is already covered by /stats in step 6.
  • DB owner mismatch → G4 (write failures incoming).
  • Low disk on the DB or code volume → flag; SQLite + backups + logs grow.

8. Healthchecks.io monitors (reference — read the dashboard)

These are external and their config lives only in the dashboard (not in the repo). Report whether each matches the intended config in the monitoring table below; a mismatch is itself a finding (it's how the schema-audit flap crept in).

Status sweep output

Patcher API status — <date/time>

  patcher-api.service    ✅ active, 0 restarts in 6h
  cloudflared            ✅ connected
  catalog-refresh timer  ✅ last run clean, next 04:00 UTC
  schema-audit timer     ✅ audit clean, next 06:00 UTC
  deploy path            ✅ watching (last deploy 3d ago — normal, event-driven)
  /health                ✅ ok
  /stats last_refresh    ✅ 8h ago (< 26h)
  /apps                  ✅ non-empty
  database               ✅ patcher:patcher, not locked
  disk                   ✅ 62% used on /var/lib
  Healthchecks config    ⚠️  schema-audit schedule drift — see note

Overall: 🟡 one config drift, no service impact.
<then: the specifics + recommended fix for any yellow/red>

Green when everything's nominal. Yellow for config drift or soft signals with no user impact. Red for an actual outage or failed job. Always end with the concrete fix for anything not green.


Monitoring topology & "don't panic" notes

The three Healthchecks.io dead-man's switches plus one external Lambda. The intended config below is the source of truth — Healthchecks stores it only in its dashboard, so drift between this table and the dashboard is a real finding.

CheckPing sourceIntended configMeaning
patcher-catalog-refreshpatcher-catalog-refresh.service (timer, 04:00 UTC)Schedule 0 4 * * *, grace 2hDaily ingest+stitch ran and succeeded
patcher-schema-auditpatcher-schema-audit.service (timer, 06:00 UTC)Schedule 0 6 * * *, grace 2hDaily schema-drift audit ran clean
patcher-deploypatcher-deploy.service (event-driven)Period 30d, grace 20mA deploy, when one runs, succeeded

External: an AWS Lambda probes /stats and alerts if last_refresh > 26h — independent liveness/freshness watch, separate from the box-side pings.

Don't-panic note 1 — patcher-deploy is outcome-only, not cadence. Deploys fire only when CI (push to main under api/**) POSTs /admin/deploy, which touches the sentinel and runs patcher-deploy.service. Deploys are therefore event-driven; there is no cadence. The check's long period exists so that a quiet stretch with no merges does not alarm. "Deploy DOWN: success signal did not arrive on time" with a week+ since the last ping is a false positive from a mis-modeled period, not a broken deploy. A real deploy problem shows up as a /fail ping (immediate) or a /start with no finish inside grace (a hang). Only those warrant action.

Don't-panic note 2 — schema-audit schedule must track the 06:00 UTC timer. If the audit flaps DOWN then UP within seconds each day, the Healthchecks schedule has drifted from the timer's actual run time. The timer runs at 06:00 UTC, so the schedule must be 0 6 * * *. A grace shorter than (schedule-to-actual-ping gap) causes the momentary flap. This is a dashboard fix, not a code fix.

Why config drift is invisible: systemd unit timings live in version control (api/deploy/*.timer); Healthchecks schedules/grace live only in the dashboard. When a timer moves in git and the dashboard doesn't follow, nothing catches it. Treat the table above as the reconciliation source.


Mode B: troubleshooting

Input shapes

Accept either:

  1. Symptom description - "API returns 502 through cloudflared", "service won't start", "keyring import fails on boot", "admin endpoints return 401 with the right token".
  2. Pasted logs - `journalctl -u

Content truncated.

When not to use it

  • When state changes are required on the production system
  • When the user lacks `systemd-journal` group membership for journal reads
  • When the user lacks read/traverse permissions on `/var/lib/patcher-api` for DB-file inspection

Limitations

  • All actions are read-only and do not modify the production system or Healthchecks.io dashboard
  • The skill does not write a Dockerfile into the repo
  • The skill does not debug the Patcher client or diagnose Jamf Pro API issues

How it compares

This skill provides a structured, read-only diagnostic workflow for a specific API service, offering targeted troubleshooting for known issues, unlike general system monitoring that may not provide specific remedies.

Compared to similar skills

api-ops side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
api-ops (this skill)024dReviewIntermediate
distributed-tracing52moNo flagsIntermediate
common-technical-practices22moNo flagsIntermediate
azure-eventhub-dotnet12moReviewIntermediate

Try saying

Example prompts that trigger this skill in your AI assistant.

You might also like

distributed-tracing

wshobson

Implement distributed tracing with Jaeger and Tempo to track requests across microservices and identify performance bottlenecks. Use when debugging microservices, analyzing request flows, or implementing observability for distributed systems.

577

common-technical-practices

TencentBlueKing

通用技术实践指南,涵盖 AOP 切面、分布式锁、重试机制、参数校验、性能监控、定时任务、审计日志等后端开发中的常见技术实践。当用户需要实现横切关注点、处理并发控制、配置重试策略、添加性能监控或实现审计功能时使用。

26

azure-eventhub-dotnet

microsoft

Azure Event Hubs SDK for .NET. Use for high-throughput event streaming: sending events (EventHubProducerClient, EventHubBufferedProducerClient), receiving events (EventProcessorClient with checkpointing), partition management, and real-time data ingestion. Triggers: "Event Hubs", "event streaming", "EventHubProducerClient", "EventProcessorClient", "send events", "receive events", "checkpointing", "partition".

11

azure-monitor-opentelemetry-ts

microsoft

Instrument applications with Azure Monitor and OpenTelemetry for JavaScript (@azure/monitor-opentelemetry). Use when adding distributed tracing, metrics, and logs to Node.js applications with Application Insights.

11

python-observability

wshobson

Python observability patterns including structured logging, metrics, and distributed tracing. Use when adding logging, implementing metrics collection, setting up tracing, or debugging production systems.

11

websocket-management

dadbodgeoff

Production-grade WebSocket connection management with connection limits, user-to-connection mapping, ping/pong health verification, and automatic stale connection cleanup.

00

Search skills

Search the agent skills registry