Install
$ agentstack add skill-knoxops-open-devops-skills-metrics-collector ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Input Parameters
| Name | Type | Required | Description | |------|------|----------|-------------| | rundir | string | Yes | Working directory absolute path for input/output files | | sshkeypath | string | No | SSH key path for cloud tags queries and reachability checks | | taskid | string | Yes | Task ID for progress tracking in scan_episodes.json |
Execution Flow
Task Context
Before starting execution, initialize task_context.json:
{
"task_id": "",
"current_step": 0,
"current_step_id": null,
"status": "running",
"steps": {
"layer_a1_discovery": "pending",
"layer_a2_exclusion": "pending",
"layer_b1_metrics": "pending",
"layer_b2_exclusion": "pending",
"finalize_output": "pending",
"review_signals": "pending"
},
"updated_at": ""
}
Update this file after each step completes. On error, set step status to "failed" and overall status to "failed".
Step 1: layera1discovery
Type: inline Description: Layer A.1: Discover all resources via cloud CLI and API tools per entity_type
Execution
Follow these instructions:
Read {rundir}/intentdetection.json and {rundir}/connectionconfig.json. Discover all cloud resources in scope. For each resource, extract: resourceid, resourcename, entitytype, resourcetype, environment, tags, provisionedat, privateip, status, spec, cost. For compute resources, also detect virttype (lxc/kvm/bare-metal/unknown). Estimate monthly cost from spec: vCPU × $20 + RAMGB × $3 + disk_GB × $0.10.
Write {rundir}/layerarawresources.json. Update {rundir}/scanepisodes.json with scanstatus="phase1layera1completed".
Progress Tracking
After completing this step, update task_context.json:
- Set
current_step_idto"layer_a1_discovery" - Set
steps.layer_a1_discoveryto"completed"
Step 2: layera2exclusion
Type: inline Description: Layer A.2: Apply coarse exclusion rules to Layer A candidates
Execution
Follow these instructions:
Apply coarse exclusion rules to filter out obviously non-candidate resources.
Input: {rundir}/layerarawresources.json
Exclusion rules (deterministic):
- New resources: provisionedat within N days -> exclude, reason="newresource".
N depends on environment: dev=1 day, staging=3 days, prod=7 days. If environment is unknown, default to 7 days.
- Non-ready status: status in [terminated, deleting, creating] -> exclude, reason="not_ready"
- DR/backup tags: tags contain purpose=disaster-recovery or purpose=backup -> exclude, reason="drbackuptag"
- Recent CI/CD deployment: if the workload has been deployed via the user's CI/CD tool within N days -> exclude, reason="active_cicd". N depends on environment: dev=7, staging=30, prod=90. If no CI/CD tool is configured, skip this rule. For K8s workloads without CI/CD access, check ReplicaSet creation timestamps as a proxy.
LLM semantic check (supplemental, for resources not already excluded):
- Check if resource name contains dr-, backup-, standby- prefix
- Check if tags contain role=standby, usage=backup
- If matched, mark as "potentialdrbackup" but still include in candidates
Write the output to the specified output file.
Output
- Schema: schemas/layer-a-candidates.schema.json
- File: layeracandidates.json
Progress Tracking
After completing this step, update task_context.json:
- Set
current_step_idto"layer_a2_exclusion" - Set
steps.layer_a2_exclusionto"completed"
Step 3: layerb1metrics
Type: inline Description: Layer B.1: Collect idle/zombie detection signals per resource type
Execution
Follow these instructions:
Collect idle/zombie detection signals for each resource in {rundir}/layera_candidates.json.
For signal definitions and per-resource-type thresholds, read prompts/signals-*.md.
Collect idle detection signals for each Layer A candidate based on its resource_type.
Input: {rundir}/layera_candidates.json
Signal rules by resource type (read the reference file for detailed thresholds and edge cases): | resourcetype | Reference file | |--------------|---------------| | compute | $PLUGINS/ico/skills/metrics-collector/prompts/signals-compute.md | | database, cache | $PLUGINS/ico/skills/metrics-collector/prompts/signals-database.md | | storage | $PLUGINS/ico/skills/metrics-collector/prompts/signals-storage.md | | network | $PLUGINS/ico/skills/metrics-collector/prompts/signals-network.md | | k8sworkload | $PLUGINS/ico/skills/metrics-collector/prompts/signals-k8s-workload.md | | k8sservice, k8sorphan | $PLUGINS/ico/skills/metrics-collector/prompts/signals-k8s-service.md | | object_storage | $PLUGINS/ico/skills/metrics-collector/prompts/signals-object-storage.md | | domain | no signals available; mark unmeasurable, skip to manual review |
CRITICAL — Threshold source: All signal thresholds, units, and collection methods come ONLY from the $PLUGINS/ico/skills/metrics-collector/prompts/signals-{type}.md reference files. DO NOT use thresholds from scanplan.json, intentdetection.json, or any other file. DO NOT add extra signals (memory, disk_io, connections) beyond what the reference file defines. Collect ONLY the signals listed in the table above.
Execution:
- For each candidate, determine resource_type
- Read the corresponding reference file for signal definitions, thresholds, and data sources
- Collect signals using available cloud CLI tools (cloud monitoring API preferred over in-VM /proc)
- For each signal, record: value, threshold, thresholdunit, isactive (value exceeds threshold → true), reliability, data_source
- Downstream consumers read
is_activeandthresholddirectly — do NOT make them guess or derive from signal values
Rules:
- Data collection fails → reliability=0.0, data_source="failed"
- ALL signals fail → "unmeasurable", do NOT classify as zombie
- Batch timeout → retry once; still failing → reliability=0.0 for that signal
Write the output to the specified output file.
Output
- Schema: schemas/layer-b-candidates.schema.json
- File: layerbraw_signals.json
Progress Tracking
After completing this step, update task_context.json:
- Set
current_step_idto"layer_b1_metrics" - Set
steps.layer_b1_metricsto"completed"
Step 4: layerb2exclusion
Type: inline Description: Layer B.2: Apply per-type signal rules to identify zombie candidates
Execution
Follow these instructions:
Apply idle detection rules per resource_type to determine zombie candidates.
Input: {rundir}/layerbrawsignals.json
The Rule (same for all resource types):
- ANY signal exceeds its threshold (defined in prompts/signals-{type}.md) → ACTIVE → exclude
- ALL signals below threshold → CANDIDATE (potential zombie)
- ALL signals reliability=0.0 → UNMEASURABLE → separate array, do NOT classify
Edge cases:
- Signal reliability=0.0 for some but not all signals: treat failed ones as "below threshold". Mark lowconfidencesignals=true
- Borderline values: check threshold range in the reference file. Mark lowconfidencesignals=true
- resource_type with no reference file (e.g. domain): mark unmeasurable, skip
Write the output to the specified output file.
Output
- Schema: schemas/layer-b-candidates.schema.json
- File: layerbcandidates.json
Progress Tracking
After completing this step, update task_context.json:
- Set
current_step_idto"layer_b2_exclusion" - Set
steps.layer_b2_exclusionto"completed"
Step 5: finalize_output
Type: inline Description: Finalize output, collect candidate context info, and update progress
Execution
Follow these instructions:
Finalize output, collect candidate context, and update tracking.
Verification: Verify {rundir}/layeracandidates.json and {rundir}/layerbcandidates.json exist and are valid JSON.
Candidate context: For each candidate, collect and append as context_info block:
- Owner: from resource tags / cloud audit logs / IaC git blame / cloud tags
- Blast radius: what depends on this resource, what would break if deleted
- Reachability: for compute, check SSH/API access and record reachable status
Update: Set scanepisodes.json → scanstatus: "phase1discoverycomplete", completed_at.
Log summary: Layer A/B counts, filter rates, excluded_reasons, tool failures, skipped types.
Edge case: 0 candidates → scanstatus "phase1discoverycompletezerocandidates" or "all_active".
Progress Tracking
After completing this step, update task_context.json:
- Set
current_step_idto"finalize_output" - Set
steps.finalize_outputto"completed"
Step 6: review_signals
Type: inline Description: Validate Phase A output before passing to screener (BLOCKING)
Execution
Follow these instructions:
Read these output files and validate them before completing this skill:
layerbrawsignals.json — every signal MUST have: value, threshold, thresholdunit, isactive, reliability, datasource layerbcandidates.json — all required schema fields present: candidates[], total counts, filter_rate
If any field is missing or any value is a placeholder ("N/A", "NONE", "0.00 MB" without real data), mark that resource as unmeasurable. Fix any issues before completing. BLOCKING.
Progress Tracking
After completing this step, update task_context.json:
- Set
current_step_idto"review_signals" - Set
steps.review_signalsto"completed"
Error Handling
zerocandidatesafterlayera
candidatescount == 0 after Layer A.2 → log warning, write empty candidates, skip Layer B, scanstatus=phase1discoverycompletezerocandidates
zerocandidatesafterlayerb
layerbcandidatescount == 0 after Layer B.2 → normal for healthy infra, write empty candidates, scanstatus=phase1discoverycompleteallactive
tool_unavailable
cloud CLI tool fails for one entitytype → skip it, record in skippedentity_types[], continue. All fail → abort.
singlesignalcollection_failure
1-3 signals fail (at least 1 has real data) → reliability=0.0 + datasource=failed. During B.2 exclusion: treat as below threshold, mark lowconfidence_signals=true.
allsignalsfailed
ALL signals placeholder or failed → UNMEASURABLE. Write to unmeasurable_hosts[], do NOT classify as zombie. > 30% unmeasurable → abort (collection method broken).
batchtimeoutinlayerb
Batch query timeout → retry once with smaller batch. Still failing → all affected resources reliability=0.0 for that signal, continue.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: KnoxOps
- Source: KnoxOps/open-devops-skills
- License: Apache-2.0
- Homepage: https://knoxops.app?invite_token=GITHUB26
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.