$npx -y skills add KnoxOps/open-devops-skills --skill decision-handlerFinal phase of the zombie resource cleanup workflow. Presents all Phase 2 findings (deep scan + observation) to the user for final human decision, executes confirmed deletions, and delivers a cost savings report.
| 1 | ## Input Parameters |
| 2 | |
| 3 | | Name | Type | Required | Description | |
| 4 | |------|------|----------|-------------| |
| 5 | | run_dir | string | Yes | Workspace root directory for file passing between agents | |
| 6 | | task_id | string | Yes | Task ID for progress tracking | |
| 7 | | ssh_key_path | string | No | SSH key path for cloud provider access | |
| 8 | |
| 9 | ## Execution Flow |
| 10 | |
| 11 | ### Task Context |
| 12 | |
| 13 | Before starting execution, initialize `task_context.json`: |
| 14 | |
| 15 | ```json |
| 16 | { |
| 17 | "task_id": "<task_id from input>", |
| 18 | "current_step": 0, |
| 19 | "current_step_id": null, |
| 20 | "status": "running", |
| 21 | "steps": { |
| 22 | "load_and_merge": "pending", |
| 23 | "generate_decision_report": "pending", |
| 24 | "write_phase5_decision": "pending", |
| 25 | "execute_decisions": "pending", |
| 26 | "deliver_final_report": "pending" |
| 27 | }, |
| 28 | "updated_at": "<ISO timestamp>" |
| 29 | } |
| 30 | ``` |
| 31 | |
| 32 | Update this file after each step completes. On error, set step status to `"failed"` and overall `status` to `"failed"`. |
| 33 | |
| 34 | ### Step 1: load_and_merge |
| 35 | |
| 36 | **Type:** agent |
| 37 | **Description:** Load all Phase 2 outputs and merge into a unified per-resource view. |
| 38 | Sorted by cost descending for prioritization. |
| 39 | |
| 40 | |
| 41 | ## Input Files |
| 42 | - `analysis/deep_scan_{resource_id}.json` |
| 43 | - `observe/observation_{resource_id}.json` |
| 44 | - `observe/observation_batch_summary.json` |
| 45 | |
| 46 | ## Execution |
| 47 | Launch an independent agent with the following prompt file: |
| 48 | |
| 49 | **Dispatch instruction:** |
| 50 | |
| 51 | Load and merge all Phase 2 outputs into a single unified view. |
| 52 | |
| 53 | ## Inputs to read |
| 54 | |
| 55 | 1. **Deep scan profiles** - glob `{run_dir}/analysis/deep_scan_*.json` |
| 56 | Each file contains detailed technical profile for one candidate resource: |
| 57 | - resource_id, resource_type, entity_type, cloud_provider |
| 58 | - spec (CPU/memory/disk), actual_utilization |
| 59 | - running_processes, open_ports, installed_packages |
| 60 | - owner_detail, team_lead_id |
| 61 | - business_context (application, system, scheduled_tasks) |
| 62 | - cost (monthly, yearly - either from cloud billing or estimated) |
| 63 | - tags, environment |
| 64 | |
| 65 | 2. **Observation reports** - glob `{run_dir}/observe/observation_*.json` |
| 66 | Each file contains isolation observation results: |
| 67 | - resource_id |
| 68 | - isolation_method, isolation_start/end dates |
| 69 | - observation_result: passed / failed / uncertain |
| 70 | - alert_count, complaint_count |
| 71 | - anomaly_events (if any), rollback_triggered |
| 72 | - observation_period_days |
| 73 | |
| 74 | 3. **Observation batch summary** - `{run_dir}/observe/observation_batch_summary.json` |
| 75 | High-level summary of all observations (results histogram, rollback count). |
| 76 | |
| 77 | ## Merge logic |
| 78 | |
| 79 | For each unique resource_id found across deep scan files: |
| 80 | - If both deep_scan + observation exist: merge full profile |
| 81 | - If only deep_scan exists (observation not yet done): mark observation_result = "pending" |
| 82 | - If only observation exists (deep scan missing): include with available data, mark spec = "incomplete" |
| 83 | |
| 84 | ## Recommendation logic |
| 85 | |
| 86 | For each resource, generate an AI recommendation: |
| 87 | - **DELETE**: observation_result = "passed" (no alerts, no complaints, no rollback) |
| 88 | - **KEEP**: observation_result = "failed" OR resource has active business use |
| 89 | - **EXTEND_OBSERVATION**: observation_result = "uncertain" (some alerts but inconclusive) |
| 90 | |
| 91 | This is a preliminary recommendation - the human makes the final call. |
| 92 | |
| 93 | Sort resources by cost.monthly descending (most expensive first). |
| 94 | |
| 95 | ## Self-validation |
| 96 | |
| 97 | Before writing the output, verify: |
| 98 | - total_candidates matches resources array length |
| 99 | - All resources have required fields: resource_id, resource_type, cloud_provider, cost, observation, recommendation, recommendation_reason |
| 100 | - total_monthly_cost equals sum of all resources monthly cost |
| 101 | - observation_summary counts equal total_candidates |
| 102 | - Resources sorted by cost.monthly descending |
| 103 | |
| 104 | If any validation fails, fix the issue and re-validate. |
| 105 | |
| 106 | |
| 107 | **Agent workflow:** |
| 108 | |
| 109 | 1. Read input data from: |
| 110 | - Schema: `schemas/deep-scan.schema.json` |
| 111 | - Schema: `schemas/observation-input.schema.json` |
| 112 | - Schema: `schemas/observation-batch-summary-input.schema.json` |
| 113 | |
| 114 | 2. Execute the agent with the prompt |
| 115 | |
| 116 | 3. Write results to: |
| 117 | - File: `decision/merged_view.json` |
| 118 | |
| 119 | ## Output |
| 120 | - **Schema:** schemas/merged-view.schema.json |
| 121 | - **File:** decision/merged_view.json |
| 122 | |
| 123 | ### Progress Tracking |
| 124 | |
| 125 | After completing this step, update `task_context.json`: |
| 126 | - Set `current_step_id` to `"load_and_merge"` |
| 127 | - Set `steps.load_and_merge` to `"completed"` |
| 128 | ### Step 2: generate_decision_report |
| 129 | |
| 130 | **Type:** agent |
| 131 | **Description:** Present merged findings to the user and collect per-resource decisions. |
| 132 | Use the Write tool to produce a Markdown report in the chat. |
| 133 | |
| 134 | |
| 135 | ## Input Files |
| 136 | - `decision/merged_view.json` (from Step load_and_merge, schema: schemas/merged-view.schema.json) |
| 137 | |
| 138 | ## Execution |
| 139 | Launch an independent agent with the following prompt file: |
| 140 | |
| 141 | **Prompt file:** `$P |