nacl-tl-deploy

SkillCloud & infra

Monitor CI/CD deployment (GitHub Actions), run health checks, update YouGile. Deployment is triggered by git push (nacl-tl-ship), this skill monitors the result. Use when: deploy, check deploy status, verify deployment, or the user says "/nacl-tl-deploy".

Available today. Use it from your connected AI after setup.

Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.

Then ask your AI: use the nacl-tl-deploy skill

What this skill tells your AI

The instructions your AI receives, as published by itsalt/nacl in nacl-tl-deploy/SKILL.md and read by ahel’s review.

Contract

Inputs this skill consumes:

  • Commit SHA being deployed
  • Prior verification status by SHA (from graph or status.json, six-status vocabulary)
  • CI pipeline status (GitHub Actions)
  • Health-check results

Outputs this skill produces:

  • Headline one of: DEPLOY COMPLETE / DEPLOY HALTED — REGRESSION / DEPLOY HALTED — {NO_INFRA | RUNNER_BROKEN | UNVERIFIED | BLOCKED}
  • Health-failure halts the pipeline rather than report-and-continue

Downstream consumers of this output:

  • Human user
  • nacl-tl-deliver (staging) — reads: headline, per-task verification-status table
  • nacl-tl-release (production) — reads: headline, per-task verification-status table
  • nacl-tl-conductor — reads: headline to decide next orchestration phase
  • nacl-tl-hotfix — reads: headline to decide whether a hotfix deploy passed

Field schema each downstream consumer requires:

Headline:  DEPLOY COMPLETE
           DEPLOY HALTED — REGRESSION
           DEPLOY HALTED — NO_INFRA
           DEPLOY HALTED — RUNNER_BROKEN
           DEPLOY HALTED — UNVERIFIED
           DEPLOY HALTED — BLOCKED (clean-checkout-artifact-missing)
           DEPLOY HALTED — BLOCKED (clean-checkout-commit-mismatch)
           DEPLOY HALTED — BLOCKED (clean-checkout-<blocker_detail>)
           DEPLOY INCOMPLETE — UNVERIFIED (health probe timeout)
           DEPLOY HALTED — NO_INFRA (health contract undefined)

Per-task status table (one row per deployed SHA):
  SHA | source-task | source-verification-status | CI-status | health-status

Health-status values: PASS | FAIL | TIMEOUT | SKIPPED
CI-status values:     PASS | FAIL | SKIPPED
source-verification-status: done (PASS) | verified-pending (UNVERIFIED) | blocked | failed | not-found

Contract change discipline: If this skill's output contract changes, every downstream consumer listed above must be audited and updated in the same release. The 0.10.0→0.10.1 regression was caused by the absence of this discipline. nacl-tl-fix changed its output contract (new status vocabulary, new header strings, new Status: field) without auditing nacl-tl-reopened and nacl-tl-hotfix, which were the only two skills that consume its output. Had a ## Contract section existed in nacl-tl-fix, the update would have included a list of downstream consumers, making the audit mandatory and visible.


TeamLead Deploy — Monitor + Verify + YouGile

Your Role

You monitor deployments triggered by CI/CD pipelines (GitHub Actions) and verify they succeed. You do NOT trigger deploys directly — that happens via git push in /nacl-tl-ship. You watch the CI/CD pipeline, run health checks, and update YouGile.

Key Principle

Deploy is triggered by push (nacl-tl-ship does this).
This skill MONITORS the result and verifies health.
If health check fails → alert + suggest rollback.

Invocation

/nacl-tl-deploy --staging              # monitor staging deploy (feature branch push)
/nacl-tl-deploy --production           # monitor production deploy (main branch push)
/nacl-tl-deploy --watch                # watch currently running pipeline/workflow

Configuration Resolution

DataSource priority
Staging URLconfig.yaml → deploy.staging.url
Production URLconfig.yaml → deploy.production.url
Health endpointconfig.yaml → deploy.[env].health_endpoint (fallback: /api/health)
YouGile done columnconfig.yaml → yougile.columns.done
VPS stagingconfig.yaml → vps.staging (ip, user, ssh_key) — SSH-диагностика при сбое health-check
VPS productionconfig.yaml → vps.production (ip, user, ssh_key) — аналогично
Clean-checkout artifact.tl/clean-checkout/<commit>.json — produced by nacl-tl-deliver Step 4b. Required for every deploy (W9). Absent / mismatch / BLOCKED without exception → DEPLOY HALTED — BLOCKED (clean-checkout-*).

If deploy section missing → error (cannot monitor deployment without URL). If YouGile missing → skip task moves, report locally.


Workflow: 5 Steps

Step 0: PLATFORM DETECTION

Detect CI/CD platform from the project:

  1. Check config.yaml → deploy.ci_platform (if set, use it)
  2. Check for .github/workflows/ directory → GitHub Actions (use gh)
  3. If neither → error: no CI/CD platform detected
PlatformCLIList runsWatch runView logs
GitHub Actionsghgh run listgh run watchgh run view --log-failed

Step 1: IDENTIFY DEPLOYMENT

  1. Pre-monitor clean-checkout artifact gate (W9-ci-clean-checkout):

    Before evaluating the upstream verification gate (0a), confirm that a clean-checkout evidence artifact exists for the commit being deployed.

    commit       = the SHA selected by Step 0 / Step 1.1
    artifact     = .tl/clean-checkout/<commit>.json   (in the repo root
                   of the deploying workspace)
    
    Artifact stateDeploy action
    Present, terminal_status: PASS, commit field matches the deployed SHAProceed to step 0a (upstream verification).
    Present, commit field DOES NOT match the deployed SHAHALT: DEPLOY HALTED — BLOCKED (clean-checkout-commit-mismatch). The wave-tip evidence is for a different commit; deploy refuses to ship a commit that was never clean-checkout-verified.
    Present, terminal_status: BLOCKED, no signed exception covering the named blocker_detailHALT: DEPLOY HALTED — BLOCKED (clean-checkout-<blocker_detail>).
    Present, terminal_status: BLOCKED, signed exception covers blocker_detailProceed with a (clean-checkout-bypass) banner on the final report and an event in .tl/emergencies/ if the bypass route was emergency-mode (not exception).
    AbsentHALT unconditionally: DEPLOY HALTED — BLOCKED (clean-checkout-artifact-missing). There is NO inline override flag. The operator must (a) re-run /nacl-tl-deliver (which produces the artifact in Step 4b) or (b) file a signed exception with affected_gates: [clean-checkout-artifact-missing] for a one-shot carve-out.

    The clean-checkout artifact is the gate-quality evidence that the deployed commit was built + smoked from a fresh tree, not a warm local cache. Without a matching artifact, deploy emits BLOCKED.

0a. Pre-monitor verification gate:

Before monitoring any pipeline, confirm the code being deployed came from tasks with verified development status. Read from graph or status.json:

// Find tasks associated with the commit SHA being deployed
MATCH (t:Task)
WHERE t.commit = $commitSha
RETURN t.id AS task_id, t.status AS status

Or read .tl/status.json and .tl/conductor-state.json to find tasks associated with the branch/commit being deployed.

Task statusDeploy action
done (PASS)Proceed with deployment monitoring
verified-pending (UNVERIFIED)HALT by default: DEPLOY HALTED — UNVERIFIED (upstream verified-pending). Operator override is permitted (explicit "yes" prompt; NOT auto-confirmed by --yes). On override → headline DEPLOY APPLIED — UNVERIFIED (operator override); Task.verification_skip_reason = 'deploy operator-override'; the source Task is NOT moved to done / released (Cross-cutting principle P4).
blockedSame gate as UNVERIFIED. On override → DEPLOY APPLIED — UNVERIFIED (blocked, operator override); no source-task state movement.
failed / REGRESSIONHALT immediately: DEPLOY HALTED — REGRESSION. Do NOT proceed
Not found in graphHALT unconditionally: DEPLOY HALTED — UNVERIFIED (upstream status unknown). The previous "Warn and proceed (backward-compat)" path is removed. The operator must populate the Task node (via the appropriate dev / fix / verify skill) and re-run; there is no override that promotes unknown to verified.
  1. Read config.yaml → deploy for target environment config
  2. Find and watch the deploy pipeline via the single-authority helper (run selection, watch, and outcome classification — shared with release/deliver; pinned by nacl-core/scripts/wait-for-ci.test.sh):
    bash nacl-core/scripts/wait-for-ci.sh watch --branch {target_branch} --timeout "${ci_timeout:-600}"
    # exit 0 → CI_OK | NO_CI (no `.github/workflows`) | NO_RUN ("no deployment in progress")
    # exit 1 → CI_FAILED (the failed-log tail is already printed)
    

Step 2: ON CI FAILURE

If wait-for-ci.sh exited non-zero (CI_FAILED):

  • Report the failure reason (the tool already printed gh run view --log-failed | tail -50).
  • Suggest: "Fix the issue, then re-push with /nacl-tl-ship"
  • If YouGile → move task to Reopened with failure details

Step 3: HEALTH CHECK

After pipeline succeeds:

  1. Read health endpoint from config: config.yaml → deploy.[env].health_endpoint (fallback: /api/health — allowed only if a health contract is also defined; see step 3 below)
  2. Read deploy URL: config.yaml → deploy.[env].url
  3. Read health contract from config: config.yaml → deploy.[env].health_contract
    • health_contract must define at minimum: expected_keys (list of top-level response keys that must be present).
    • Optional: expected_values (key→value pairs that must match exactly).
    • If health_contract is absent or empty → HALT immediately: DEPLOY HALTED — NO_INFRA (health contract undefined) Do NOT proceed. A 200 response with no shape contract is unverifiable.
  4. Poll for liveness (replaces fixed sleep):
    • Probe every 2 seconds for up to 60 seconds.
    • On each probe, attempt curl -s -w "\n%{http_code}" [url][health_endpoint].
    • Stop polling as soon as the endpoint responds with HTTP 200.
    • If 60 seconds elapse with no HTTP 200 → HALT: DEPLOY INCOMPLETE — UNVERIFIED (health probe timeout)
  5. Validate response shape (required — HTTP 200 alone is not sufficient):
    BODY=$(curl -s [url][health_endpoint])
    # For each key in health_contract.expected_keys:
    echo "$BODY" | jq --exit-status 'has("[key]")'
    # For each entry in health_contract.expected_values:
    echo "$BODY" | jq --exit-status '.[key] == [expected_value]'
    
    • If any expected_keys key is absent → FAIL shape validation.
    • If any expected_values value mismatches → FAIL shape validation.
    • Shape validation failure → HALT: DEPLOY HALTED — health check failed (shape mismatch).
    • On PASS: record version field from response body if present.
  6. If shape validation passes → health-status = PASS. Proceed to Step 4.
  7. On any non-200 HTTP response during polling (not timeout): retry counts against the 60-second budget. After budget is exhausted → same DEPLOY INCOMPLETE headline.
  8. If the health endpoint never responds and config.yaml → vps.[env] is populated, run SSH diagnostics before halting:
    1. Connect: ssh -i {ssh_key} {user}@{ip}
    2. Check process manager: pm2 status or docker ps
    3. Check recent logs: journalctl -u app --since '5m ago' or docker logs --since 5m
    4. Check resources: df -h, free -m
    5. Include all findings in the failure report.
    6. HALT pipeline with the diagnostic report. Do NOT proceed to Step 4 success path.

Step 4: YOUGILE UPDATE + REPORT

The report opens with a per-task status table. One row per deployed SHA. Per-task verification status is required in every report; this is the single source of truth that downstream readers consume.

Per-task status table (mandatory — include in every report):

| SHA     | source-task | source-verification-status | CI-status | health-status |
|---------|-------------|---------------------------|-----------|---------------|
| abc1234 | UC-042      | done (PASS)               | PASS      | PASS          |
| def5678 | TECH-007    | done (PASS)               | PASS      | PASS          |
  • SHA: short commit hash (7 chars) being deployed
  • source-task: task ID from graph/status.json (or not-found if absent)
  • source-verification-status: one of done (PASS) / verified-pending (UNVERIFIED) / blocked / failed / not-found
  • CI-status: PASS / FAIL / SKIPPED
  • health-status: PASS / FAIL / TIMEOUT / SKIPPED

Followed by the aggregated headline on a line by itself:

Headline: DEPLOY COMPLETE

On success (pipeline passed AND health check passed):

  • Move task to Done (if --production) or ToRelease (if --staging)
  • Post deploy confirmation to task chat:
    Deployed to [staging/production]
    
    URL: https://example.com
    Health: 200 OK
    Version: 1.2.3
    Commit: abc1234
    Time: 2m 15s
    
    Next: /nacl-tl-release (for production deploys)
    
  • Headline: DEPLOY COMPLETE

On pipeline failure (Step 2):

  • Move task to Reopened
  • Post failure details to task chat
  • Suggest: check logs, fix, re-push
  • Headline: DEPLOY HALTED — REGRESSION (if new failures introduced) or DEPLOY HALTED — {NO_INFRA | RUNNER_BROKEN} as appropriate

On health check failure (Step 3):

  • Pipeline halted (Step 3.7 — see above); do NOT reach this step's success path
  • Move task to Reopened with health failure details
  • Headline: DEPLOY HALTED — health check failed

On pre-monitor gate halt (Step 1.0):

  • Do NOT update YouGile to Done
  • Post advisory with status detail
  • Headline: DEPLOY HALTED — UNVERIFIED / DEPLOY HALTED — REGRESSION

Without YouGile: Just report locally with headline.


CI/CD Pipeline Templates

GitHub Actions uses workflow files in .github/workflows/. Templates are in nacl-tl-core/templates/:

  • deploy-backend.yml — backend build + deploy
  • deploy-frontend.yml — frontend build + deploy

These are created during project setup by /nacl-tl-dev TECH-001 (infrastructure task) or by /nacl-init.

The templates are a Node/npm reference profile with unpinned versions. Before first use, fill ${NODE_VERSION} (and any image versions) from the project's own toolchain — config.yaml → modules.<m>.stack or the detected runtime — and replace ecosystem-specific steps if the project is not Node. NaCl never supplies a default version.


References

  • config.yaml → deploy section (URLs, health endpoints)
  • .tl/clean-checkout/<commit>.json — required clean-checkout evidence artifact produced by nacl-tl-deliver Step 4b (W9). Schema: .tl/clean-checkout/_template.json.
  • nacl-tl-ship/SKILL.md — triggers the deploy via push
  • nacl-tl-deliver/SKILL.md § "Step 4b: CLEAN-CHECKOUT GATE" — the upstream producer of the artifact this skill consumes.
  • nacl-tl-release/SKILL.md — follows after successful production deploy

Signals

GitHub stars
27
Forks
4
Last commit
Sep 2026
Advanced
Item type
skill
Key
nacl-tl-deploy
Source
github.com/itsalt/nacl