agentleFS
KhaledSaeed18KhaledSaeed18/dotclaude/skills/deployment/deploy-verification/SKILL.md

deploy-verification

Skill5 starsChanged 4 months agoMITView on GitHub

Prove a deployment from the server side. Use when a deploy finished and needs sign-off, when a rolling update may have dropped requests, or when a proxy, certificate, header or client address needs checking.

We split this skill into the rules it gives an agent

2 rules. About 0 are common, 1 is distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Never type credentials: When a signed-in check is needed, the owner signs in.

    line 13
  2. Very specific:

    A green pipeline is not a verified deploy: Read each job's conclusion and then run these checks anyway.

    line 14

≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

A deploy is verified when the certificate verifies for the name, the container matches its contract, every public probe answers, a rolling update drops nothing, and the backend sees real client addresses. Measure from the server, not from a laptop: ISP paths produce false timeouts and hide proxy behaviour.

Hard rules: never break these

  • Probe from the server over one SSH connection (ControlMaster, see the coolify-vps-baseline skill). A laptop result is a hint, not evidence.
  • Read-only on production data. Open pages, call health routes, send probes to routes that do not exist; never submit a form or an action in a live app.
  • Never type credentials. When a signed-in check is needed, the owner signs in; you navigate.
  • A green pipeline is not a verified deploy. Read each job's conclusion and then run these checks anyway.
  • Report failures with their evidence, not "looks fine": the exact command and its output.

Step 1: Certificate and routing

D=app.example.com
echo | openssl s_client -connect 127.0.0.1:443 -servername $D -verify_hostname $D -verify_return_error 2>/dev/null | grep 'Verify return code'
echo | openssl s_client -connect 127.0.0.1:443 -servername $D 2>/dev/null | openssl x509 -noout -issuer -dates
curl -s -o /dev/null -w 'healthz %{http_code}\n' https://$D/healthz
curl -s -o /dev/null -w 'api ready %{http_code}\n' https://$D/api/v1/health/ready
curl -sI https://$D/ | grep -i -E '^(strict-transport|x-frame|content-security|x-powered|server)'

Verify return code: 0 (ok) and a Let's Encrypt issuer; TRAEFIK DEFAULT CERT means DNS did not exist when the router registered (redeploy after it does). Before DNS exists, add --resolve $D:443:127.0.0.1 -k to curl to test the route anyway. Compare the header set with the previous host's (curl -sI against it) so nothing an edge used to add is lost.

Step 2: Container contract

C=$(sudo docker ps --filter label=coolify.resourceName=<app> --format '{{.Names}}' | head -1)
sudo docker inspect "$C" --format 'health={{.State.Health.Status}} mem={{.HostConfig.Memory}} ports={{.HostConfig.PortBindings}} user={{.Config.User}} image={{.Config.Image}}'
sudo docker exec "$C" id -u

Healthy, the limit in bytes, map[], a non-root user, and the immutable sha- tag the pipeline published.

Step 3: Rolling update under load

Arm the probe loop when the deploy job starts, not before (quality gates run first) and not after it ended:

# on the workstation: wait for the deploy job, then probe from the server
until [ "$(gh run view <id> --json jobs --jq '.jobs[] | select(.name=="Deploy to Coolify") | .status')" = in_progress ]; do sleep 10; done
ssh -o ControlPath=$S <alias> 'for i in $(seq 1 150); do curl -s -o /dev/null -w "%{http_code} %{time_total} $(date -u +%T)\n" --max-time 3 https://'$D'/healthz; sleep 1; done > /tmp/rollover.log; cut -d" " -f1 /tmp/rollover.log | sort | uniq -c; sort -k2 -n /tmp/rollover.log | tail -1'

Expect every line 200. Any 502 lines clustered in a window are the old container draining while the proxy still routes to it; read the deployment log (the coolify-vps-baseline skill shows the query) and fix the shutdown (the nextjs-coolify-image skill). Confirm the deploy job's start and end timestamps fall inside the probe window, or the test proved nothing.

Step 4: Client address through the proxy

Send a request to a route that does not exist with a forged X-Forwarded-For, from the server and from the workstation, then read what the backend logged for it:

curl -s -o /dev/null -H 'X-Forwarded-For: 203.0.113.9' https://$D/api/v1/zzz-probe-forged
A=$(sudo docker ps --filter label=coolify.resourceName=<api> --format '{{.Names}}' | head -1)
sudo docker logs --since 2m "$A" 2>&1 | grep -o 'zzz-probe-[a-z]* - IP: [0-9a-f.:]*'

The logged address must be the real peer (the server's public address, your workstation's address), never 203.0.113.9. The mechanism is the proxy-client-address skill.

Step 5: Signed-in pages

With the owner signed in, open the landing page, one data-heavy page and one page per locale; read the network log for same-origin /api/ calls answering 200 and for any cross-origin call (there should be none when the app proxies its API). Note long-lived streams: they are what makes shutdown timing matter.

Produce a checklist with one line per check: command, expected, observed, pass or fail. Record it in the project's deployment doc with the date.

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.

Reviews can't be read right now.

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.