---
name: eck:deploy
version: "0.7.4"
description: "Deployment orchestrator: promote dev to main, release tagging, changelog generation, and production verification. Consumes validated code on dev branch."
disable-model-invocation: false
---

# Deploy

Promote validated code from dev to main, create releases, and verify production readiness. Consumes the merged PR artifact from the validate phase.

Usage: `/eck:deploy [--promote-only | --status] [--rigor lite|standard|strict] [--force]`

---

## Context Budget — Agent Dispatch Required

> **Stages 2–3 MUST dispatch their sub-skills via the Agent tool**, not inline invocation. The deploy orchestrator is lightweight (5 stages) but promotion and release stages can produce verbose git output and changelog content. Agent dispatch keeps the orchestrator lean enough to complete the review gate at Stage 4.

---

## Sub-skill Dispatch Table

| Sub-skill      | Invocation                                | Purpose                         |
| -------------- | ----------------------------------------- | ------------------------------- |
| deploy-promote | `/<PROJECT_KEY_LOWERCASE>:deploy-promote` | Merge dev to main (promotion)   |
| deploy-release | `/<PROJECT_KEY_LOWERCASE>:deploy-release` | Tag + changelog + release notes |
| deploy-tracker | `/<PROJECT_KEY_LOWERCASE>:deploy-tracker` | Update tracker issue status     |
| deploy-status  | `/<PROJECT_KEY_LOWERCASE>:deploy-status`  | Multi-repo dashboard            |
| deploy-review  | `/<PROJECT_KEY_LOWERCASE>:deploy-review`  | Review gate (mandatory)         |

> **Sub-skill invocation rule:** All sub-skills above MUST be invoked with the project key prefix derived from `PROJECT_KEY` in `.claude/project-constants.md`. For example, if `PROJECT_KEY=WA`, invoke `/wa:deploy-promote`, not `/deploy-promote`.

---

## Visual Framework

Follow the visual framework defined in the `output:visual-framework` primitive.

---

## Task Registration

| Stage | Subject            | Active Form        | Statusline      |
| ----- | ------------------ | ------------------ | --------------- |
| 1     | Stage 1: Calibrate | Calibrating deploy | Calibrate (1/5) |
| 2     | Stage 2: Promote   | Promoting to main  | Promote (2/5)   |
| 3     | Stage 3: Release   | Creating release   | Release (3/5)   |
| 4     | Stage 4: Review    | Reviewing deploy   | Review (4/5)    |
| 5     | Stage 5: Tracker   | Updating tracker   | Tracker (5/5)   |

## Usage

```bash
/eck:deploy                      # Promote dev->main + release (default)
/eck:deploy --promote-only       # Stop after promotion (no release)
/eck:deploy --status             # Multi-repo dashboard only
/eck:deploy --rigor lite         # Override development mode
/eck:deploy --rigor standard
/eck:deploy --rigor strict
--force                          # Override prerequisite gate check (not available at strict rigor)
```

---

## Flags

| Flag                             | Behavior                                                         |
| -------------------------------- | ---------------------------------------------------------------- |
| `--promote-only`                 | Stop after promotion (no release)                                |
| `--status`                       | Dashboard only — invoke deploy-status and exit                   |
| `--rigor lite\|standard\|strict` | Override development rigor for this run                          |
| `--force`                        | Override prerequisite gate check (not available at strict rigor) |

---

## Stage 0: Gate Check

> **Pre-execution prerequisite validation — does not appear in Task Registration.**

### Inputs

- Feature slug from `<FEATURE_SLUG>` or `$ARGUMENTS`
- `--force` flag (if present)

### Activities

1. Invoke `core/ops:gate-check` primitive with:
   - `feature_slug`: current feature
   - `required_step`: `validate` (must be complete with passing review gate)
   - `rigor`: current rigor level from `core/mode:read-dev-rigor`
   - `passing_verdicts`: `PASS`, `CONDITIONAL` (both accepted for deploy)
2. Verify PR has been merged to dev branch (code exists on dev).
3. Verify CI is passing on dev branch.
4. If gate check passes: proceed to Stage 1.
5. If gate check fails:
   - **Without `--force`**: Display blocking reason and guidance. STOP.

     ```
     ⚠ Prerequisite not met: validate phase must be complete with code merged to dev.
     Current status: <status> | Gate verdict: <verdict>

     Options:
     - Complete /eck:validate first (reviews + merges PR to dev)
     - Re-run with --force to override (not available at strict rigor)
     ```

   - **With `--force`** (lite/standard only): Record override in lifecycle.json and proceed.
     At strict rigor, `--force` is rejected with: "Hard block at strict rigor — complete prerequisites first."

### Outputs

- Gate check result (pass/fail/forced)

### Exit Criteria

- Prerequisites verified OR override recorded

---

## Stage 1: Calibrate

### Inputs

- `$ARGUMENTS` (flags: `--promote-only`, `--status`, `--rigor`, `--force`)
- `docs/{feature}/DEPLOY-STATE.md` (if a previous session exists)
- Active feature slug from lifecycle.json

### Activities

```bash
bash $ECK_HOME/update-stage.sh "Calibrate (1/5)"
```

### 1.1: Check for Existing State

Check for a state file from a previous session:

```bash
FEATURE_ID=$(node $ECK_HOME/update-lifecycle.js read 2>/dev/null | node -e "const d=JSON.parse(require('fs').readFileSync(0,'utf-8'));console.log(d.active_feature||'')" 2>/dev/null)
[ -z "$FEATURE_ID" ] && FEATURE_ID=$(node $ECK_HOME/manage-features.js resolve "$ARGUMENTS" 2>/dev/null | jq -r '.id // empty')
FEATURE_SLUG=$(node $ECK_HOME/manage-features.js read "$FEATURE_ID" 2>/dev/null | jq -r '.slug // empty')
cat "$CLAUDE_PROJECT_DIR/docs/${FEATURE_ID}-${FEATURE_SLUG}/DEPLOY-STATE.md" 2>/dev/null || echo "No state file"
```

If found, offer resume via AskUserQuestion:

```
Found DEPLOY-STATE.md from a previous session.
Options:
  1 - Resume from where you left off
  2 - Start fresh (discard previous state)
```

If resume: load state, skip completed stages, resume from the last incomplete stage.

### 1.2: Resolve Development Mode

Resolve the active development mode using the `mode:read-dev-rigor` primitive. If
`--rigor` is present in `$ARGUMENTS`, override the project default for this run.

### 1.3: Parse Flags

Parse `$ARGUMENTS` to determine the stop point and any mode override:

| Flag             | Stop Point                                   |
| ---------------- | -------------------------------------------- |
| `--status`       | Invoke `/deploy-status` and exit immediately |
| `--promote-only` | Stop after Stage 2 (Promote)                 |
| _(none)_         | Default: run all stages (promote + release)  |

### 1.4: Handle --status Flag

If `--status` is present, invoke `/deploy-status` and exit:

```bash
source $ECK_HOME/colors.sh
printf '%b\n' "${CYAN}[*]${RESET} Invoking deploy-status dashboard"
```

After `/deploy-status` completes, reset the statusline and exit:

```bash
bash $ECK_HOME/update-stage.sh
```

### 1.5: Verify Dev Branch

Verify that the dev branch contains the expected merged code:

```bash
git log {DEV_BRANCH} --oneline -5
```

If the dev branch has no recent merges, display a warning.

### 1.6: Display Deployment Plan

Display the deployment plan summary via the Bash tool:

```bash
source $ECK_HOME/colors.sh

echo ""
printf '%b\n' "${ORANGE}${BOLD}Deployment Plan${RESET}"
echo ""
printf '%b\n' "Mode: {DEV_RIGOR}"
printf '%b\n' "Stop point: {STOP_POINT}"
printf '%b\n' "Branch: {DEV_BRANCH}"
echo ""
```

### Outputs

- Resolved development mode, stop point, and feature slug

### Exit Criteria

- Deployment plan displayed; lifecycle entry registered; ready to proceed to Stage 2

---

## Stage 2: Promote

### Inputs

- Dev branch with merged, validated code
- Main branch target

### Activities

```bash
bash $ECK_HOME/update-stage.sh "Promote (2/5)"
```

1. Switch to `<DEV_BRANCH>` if not already on it.

2. Pull latest changes:

   ```bash
   git pull origin {DEV_BRANCH}
   ```

3. **MUST** dispatch `/<PROJECT_KEY_LOWERCASE>:deploy-promote` via the **Agent tool** to keep orchestrator context lean.

   The Agent prompt should instruct the subagent to:
   - Run the deploy-promote sub-skill to merge `<DEV_BRANCH>` into `<MAIN_BRANCH>`
   - Return a **compact summary only**: merge strategy used, commit count, merge SHA
   - Do NOT return full git log or diff output

4. Display promotion result:

```bash
source $ECK_HOME/colors.sh
printf '%b\n' "${GREEN}[x]${RESET} Promoted: {DEV_BRANCH} -> {MAIN_BRANCH}"
```

On failure:

```bash
source $ECK_HOME/colors.sh
printf '%b\n' "${RED}[!]${RESET} deploy-promote failed — promotion halted"
printf '%b\n' "    ${DIM}Address the error and re-run /eck:deploy.${RESET}"
```

Then reset the statusline and STOP.

### 2.1: Evaluate Stop Point

If the stop point is `--promote-only`, display completion summary and exit:

```bash
source $ECK_HOME/colors.sh

echo ""
printf '%b\n' "${ORANGE}${BOLD}Promotion Complete${RESET}"
echo ""
printf '%b\n' "Promoted: {DEV_BRANCH} -> {MAIN_BRANCH}"
echo ""
printf '%b\n' "${BOLD}Next Step${RESET}"
printf '%b\n' "${DIM}  /eck:deploy  (to create release)${RESET}"
```

Then reset the statusline and exit.

### Outputs

- Dev branch promoted to main

### Exit Criteria

- Main branch contains the promoted code, or error displayed and skill stops

---

## Stage 3: Release

### Inputs

- Main branch with promoted code from Stage 2
- Version number from project configuration

### Activities

```bash
bash $ECK_HOME/update-stage.sh "Release (3/5)"
```

### 3.1: Invoke Sub-skill

**MUST** dispatch `/<PROJECT_KEY_LOWERCASE>:deploy-release` via the **Agent tool** to keep orchestrator context lean.

The Agent prompt should instruct the subagent to:

- Run the deploy-release sub-skill (tag, changelog, release notes)
- Return a **compact summary only**: version tag, commit count in release, changelog entry count
- Do NOT return full changelog or release notes content

`/deploy-release` is responsible for:

- Creating a git tag from the version (e.g., `v1.2.0`)
- Generating a changelog from commit history
- Creating release notes using the technical-writer agent

### 3.2: Pre-Review Release Summary

After `/deploy-release` completes, display the release summary box via the
Bash tool:

```bash
source $ECK_HOME/colors.sh

echo ""
printf '%b\n' "${ORANGE}${BOLD}Release Complete${RESET}"
echo ""
printf '%b\n' "Version tag: {VERSION_TAG}"
printf '%b\n' "Changelog: {CHANGELOG_ENTRY_COUNT} entries"
printf '%b\n' "Release URL: {RELEASE_URL}"
echo ""

printf '%b\n' "${BOLD}Changelog Entries${RESET}"
# For each changelog entry produced by deploy-release:
printf '%b\n' "${GREEN}[x]${RESET} {CHANGELOG_ENTRY}"
echo ""
```

### 3.3: Registry Update

**Reference:** `ops:registry-update` primitive for the canonical read-modify-write procedure.

If registry does not exist, log warning and skip this step.

Append a `sync_history` entry to `$ECK_HOME/registry.yaml`:

```yaml
- date: "{DATE}"
  action: "deploy"
  performed_by: "/eck:deploy"
  summary: "Deployed to {MAIN_BRANCH}: promoted from {DEV_BRANCH}"
```

Set `last_modified_at` to current ISO-8601 date.
Recompute `project_summary` per the `ops:registry-update` primitive.
Use atomic write: write to `registry.yaml.tmp`, then rename to `registry.yaml`.

### Outputs

- Git tag created; changelog generated; release published; `registry.yaml` updated

### Exit Criteria

- Release artifact created and registry updated

---

## Stage 4: Review (4/5)

> **Mandatory — cannot be skipped or deselected.**

```bash
bash $ECK_HOME/update-stage.sh "Review (4/5)"
```

### Inputs

- All stage artifacts produced by prior stages
- Feature slug
- Rigor level

### Activities

1. **MUST** dispatch to `<PK>:deploy-review` sub-skill. Do NOT skip the review gate.
2. Review skill validates mandatory artifacts, runs quality checks, computes verdict.
3. Review skill **MUST** record verdict via `update-lifecycle.js gate-verdict`.
4. On PASS or CONDITIONAL:
   - Display: "Deploy gate PASSED. Deployment complete."
5. On FAIL:
   - Step status set to "gated" (yellow in statusline)
   - Display: "Deploy gate FAILED. Fix issues and re-run /eck:deploy."
   - STOP (do not display next-stage guidance)

### Outputs

- `docs/{feature}/DEPLOY-REVIEW.md` verdict artifact
- lifecycle.json updated with gate verdict

### Exit Criteria

- Review gate verdict recorded
- Step marked "done" (on PASS) or "gated" (on FAIL)

### Reset Statusline

```bash
bash $ECK_HOME/update-stage.sh
```

---

## Stage 5: Tracker

```bash
bash $ECK_HOME/update-stage.sh "Tracker (5/5)"
```

### Inputs

- Release result from Stage 3
- Feature tracker issues

### Activities

1. Invoke `/deploy-tracker --status deployed` to update tracker issue statuses.
   - On success: display `[x] Tracker issues updated to Deployed`
   - On failure: display `[!] deploy-tracker failed — update tracker manually`. Non-blocking.

### Outputs

- Tracker issues updated with "Deployed" status

### Exit Criteria

- `/deploy-tracker` completed (success or failure logged)

---

## Lifecycle Integration

### Entry Protocol (Stage 1)

At the start of Stage 1, after calibration, run:

```bash
echo "$(date +%s)" > /tmp/eck-skill-start-$$

FEATURE_ID=$(node $ECK_HOME/update-lifecycle.js read 2>/dev/null | node -e "const d=JSON.parse(require('fs').readFileSync(0,'utf-8'));console.log(d.active_feature||'')" 2>/dev/null)
[ -z "$FEATURE_ID" ] && FEATURE_ID=$(node $ECK_HOME/manage-features.js resolve "$ARGUMENTS" 2>/dev/null | jq -r '.id // empty')
FEATURE_SLUG=$(node $ECK_HOME/manage-features.js read "$FEATURE_ID" 2>/dev/null | jq -r '.slug // empty')
node $ECK_HOME/update-lifecycle.js register "$FEATURE_ID" --branch "$(git branch --show-current 2>/dev/null)"
node $ECK_HOME/update-lifecycle.js start "$FEATURE_ID" "deploy"
node $ECK_HOME/update-lifecycle.js activate "$FEATURE_ID"
```

### Exit Protocol (after Stage 5: Tracker)

```bash
START_TS=$(cat /tmp/eck-skill-start-$$ 2>/dev/null || echo "0")
END_TS=$(date +%s)
DURATION=$((END_TS - START_TS))

node $ECK_HOME/update-lifecycle.js done "$FEATURE_ID" "deploy"

node $ECK_HOME/log-activity.js \
  --skill "eck:deploy" --feature "$FEATURE_ID" --outcome "success" \
  --duration "$DURATION" --summary "{SUMMARY_TEXT}" --step "deploy"

# Mark feature completed — clears active_feature so statusline resets
node $ECK_HOME/update-lifecycle.js complete "$FEATURE_ID"

# Close the feature tracker issue via core/ops:close-feature-issue primitive
# (reads issue_number from lifecycle.json, dispatches to tracker backend, non-blocking)
```

On failure, replace `done` with `fail` and outcome with `"failed"`. Do NOT run `complete` or close the feature issue on failure.

---

## Error Handling

| Condition                                  | Behavior                                                              |
| ------------------------------------------ | --------------------------------------------------------------------- |
| No changes detected on dev                 | Display notice and STOP — nothing to deploy                           |
| deploy-promote fails                       | Display error and STOP — promotion is required                        |
| deploy-release fails                       | Display error and STOP                                                |
| deploy-tracker fails                       | Log warning and continue — tracker is non-blocking                    |
| Force push guard                           | Require explicit user confirmation before proceeding                  |
| Unexpected failure or user-initiated pause | Write state to `DEPLOY-STATE.md` using the `ops:state-save` primitive |

On unexpected failure or user-initiated pause (`/eck:pause`), write stage state to `docs/{feature}/DEPLOY-STATE.md`. The `/eck:pause` command will write this state file automatically when invoked during a deploy session.

### Force Push Guard

Force push is NEVER used without explicit user confirmation:

```bash
source $ECK_HOME/colors.sh
printf '%b\n' "${RED}[!]${RESET} Force push requested — this rewrites remote history"
printf '%b\n' "    ${DIM}Confirm: type YES to proceed, anything else to cancel.${RESET}"
```

Wait for the user to confirm. If not confirmed, reset the statusline and STOP.

### Error Display Pattern

Use this pattern for any sub-skill failure that halts the pipeline:

```bash
source $ECK_HOME/colors.sh
printf '%b\n' "${RED}[!]${RESET} {sub-skill-name} failed — deploy halted"
printf '%b\n' "    ${DIM}Address the error and re-run /eck:deploy.${RESET}"
```

At completion (success or error), always reset the statusline:

```bash
bash $ECK_HOME/update-stage.sh
```

---

## Related Documents

- `deploy-promote` — promote dev to main
- `deploy-release` — tag + changelog + release notes
- `deploy-tracker` — update tracker issue status
- `deploy-status` — multi-repo git dashboard
- `/eck:validate` — validate orchestrator (lifecycle predecessor)
- `/audit-doc-drift` — run before shipping to catch stale terminology in docs
- `scaffold/project/context/standards/terminology-glossary.md` — canonical term reference
