| name | run-deploy |
| description | Trigger deployment via GitHub Actions workflow_dispatch. Execute phase skill — validates pre-deploy conditions, fires the configured workflow, monitors completion, and verifies post-deploy health. |
| ooda_phase | execute |
| version | 1.1.0 |
| input | {"files":["agent/state/service_health.json","agent/state/test_coverage.json"],"config_keys":["deploy_workflow","deploy_workflow_inputs","deploy_monitor_timeout_seconds","deploy_health_wait_seconds","health_endpoints","safety.halt_file"]} |
| output | {"files":["agent/state/deploy.json"]} |
| safety | {"halt_check":true,"read_only":false,"branch_prefix":"auto/deploy/","cost_limit_usd":0.05} |
| domains | ["service_health"] |
| chain_triggers | [{"target":"scan-health","condition":"health_check == 'failed'","note":"Trigger health monitoring after a failed post-deploy health check"}] |
run-deploy: GitHub Actions Deployment Trigger
The "hand" of the harness. Validates deployment readiness, fires the configured
GitHub Actions workflow via workflow_dispatch, monitors completion, and
verifies the service is healthy afterward.
- NEVER auto-invoked without passing the full pre-deploy checklist
- Requires explicit conditions — does not deploy blindly
- Writes results to
agent/state/deploy.json
Safety Rules
- HALT file — Mandatory first check. If present, print reason and stop.
- Pre-deploy checklist — All six conditions must pass before triggering.
- gh required — Cannot deploy without GitHub CLI. If unavailable, error and exit.
- No blind deploys —
config.deploy_workflow must be explicitly configured.
Step 0: Safety
0-A: HALT Check
if file exists at config.safety.halt_file:
Print "[HALT] run-deploy stopped. Reason: {file_content}"
EXIT immediately.
0-B: Config Validation
if config.deploy_workflow is missing, null, or empty:
Print "No deploy workflow configured. Skipping."
EXIT cleanly (not an error).
Step 1: Pre-Deploy Checklist
All six conditions must pass. On first failure, print the reason and skip deployment.
| # | Check | Source | Pass Condition |
|---|
| 1 | No critical health alerts | agent/state/service_health.json | alerts has no item with severity == "critical" |
| 2 | Tests passing | agent/state/test_coverage.json | status == "passing" |
| 3 | No HALT file | config.safety.halt_file | File does not exist (re-confirmed) |
| 4 | Complexity level | config.json | progressive_complexity.current_level >= 3 OR invoked directly by user |
| 5 | Clean working tree | git status --porcelain | Output is empty (no uncommitted changes) |
| 6 | Workflow file exists | .github/workflows/{deploy_workflow} | File exists in the repository (prevents cryptic GitHub API errors) |
On any failure:
Pre-deploy checklist FAILED: {reason}
Deployment skipped.
State files missing (health, tests) count as unknown — treat as failure for that check.
Print which specific check failed so the user can act on it.
Step 2: Trigger Deployment
Verify gh is available and authenticated:
gh --version
gh auth status
If not found: print ERROR: gh (GitHub CLI) is required for deployment. Install from https://cli.github.com/ and exit non-zero.
If not authenticated: print ERROR: gh is not authenticated. Run: gh auth login and exit non-zero.
Determine the current branch:
git rev-parse --abbrev-ref HEAD
Trigger the workflow. If config.deploy_workflow_inputs is set (object of key-value
pairs), pass each entry as -f key=value:
gh workflow run {config.deploy_workflow} --ref {branch}
gh workflow run {config.deploy_workflow} --ref {branch} -f environment=staging -f tag=v1.2.3
Wait up to 15 seconds for the run to register, then retrieve the run ID:
gh run list --workflow={config.deploy_workflow} --limit=1 --json databaseId,url --jq '.[0]'
Print:
Deployment triggered: {config.deploy_workflow} on {branch}
Workflow run: {run_url}
Step 3: Monitor
Watch the run until completion. Timeout is read from
config.deploy_monitor_timeout_seconds (default 600 — 10 minutes):
gh run watch {run_id} --exit-status
- Exit 0 →
status: "success"
- Non-zero exit →
status: "failed"
- Timeout (> configured seconds): kill watch, record
status: "unknown", print:
Deployment monitor timed out after {timeout}s. Check {run_url} manually.
Re-check the HALT file after the wait completes. If it appeared during the long
monitor window, record status: "halted" and skip post-deploy steps.
Step 4: Post-Deploy Health Check
Skip this step if config.health_endpoints is missing or empty — note the skip.
If endpoints are configured:
- Wait
config.deploy_health_wait_seconds (default 30) for the service to stabilize.
- Run health checks using the same logic as
scan-health (Step 2 of that skill).
- If any endpoint fails, retry once after another
deploy_health_wait_seconds wait
(services with rolling deploys may need extra time).
- Evaluate final results:
- All endpoints 200 →
health_check: "passed" — print Deployment verified healthy.
- Any endpoint non-200 or critical alert after retry →
health_check: "failed" — print:
ALERT: Post-deploy health check failed after retry. Consider rollback.
Step 5: State Update + Report
Write to agent/state/deploy.json:
{
"schema_version": "1.1.0",
"last_deploy": "<ISO 8601>",
"deploy_count": N,
"status": "success|failed|unknown|halted",
"workflow": "{config.deploy_workflow}",
"branch": "{branch}",
"commit_sha": "{HEAD short SHA at trigger time}",
"run_id": "{run_id}",
"run_url": "{run_url}",
"health_check": "passed|failed|skipped",
"health_retry_count": 0,
"duration_seconds": N,
"error_message": null
}
deploy_count: increment from previous value in the file (default 0 if file absent).
commit_sha: captured via git rev-parse --short HEAD before triggering.
duration_seconds: wall-clock time from trigger to final state write.
error_message: null on success; short description on failure/unknown.
Print deployment summary:
run-deploy — <ISO timestamp>
Workflow : {config.deploy_workflow}
Branch : {branch}
Commit : {commit_sha}
Run ID : {run_id}
Status : success | failed | unknown | halted
Health : passed | failed | skipped
Duration : {duration_seconds}s
Run URL : {run_url}
If status == "failed": print Workflow failed. Investigate at {run_url} before retrying.
If status == "halted": print HALT file appeared during deployment. Monitoring stopped.
If health_check == "failed": print Post-deploy health check failed after retry. Manual rollback may be needed.
Graceful Degradation
| Scenario | Behavior |
|---|
| HALT file present | Print reason, exit immediately — no deployment |
| HALT file appears during monitor | Record status: "halted", skip health check, print warning |
deploy_workflow not configured | Print skip message, exit 0 |
Workflow file not found in .github/workflows/ | Print Workflow file {name} not found. Check config.deploy_workflow., exit non-zero |
deploy_workflow_inputs invalid (non-object) | Print deploy_workflow_inputs must be a key-value object., exit non-zero |
gh not installed | Print install instructions, exit non-zero |
| Pre-deploy checklist fails | Print failing check, exit 0 (not an error — a safety gate) |
| Run ID not found after trigger | Record run_id: null, status "unknown", print warning |
| Monitor timeout | Record status: "unknown", print manual check URL with configured timeout value |
| Workflow fails (non-zero exit) | Record status: "failed", capture error_message from run logs, skip health check |
| Health check fails first attempt | Retry once after deploy_health_wait_seconds, then record final result |
health_endpoints missing | Record health_check: "skipped", note in report |
service_health.json or test_coverage.json missing | Treat as checklist failure for that check |
deploy.json missing | Create fresh with deploy_count: 1 |