scout-verify
Use when the user wants a TYPED, FINGERPRINTED, IMMUTABLE evidence artifact about a Kubernetes resource — the Verify verb group of cub-scout (the receipt capability shipped in #446). Natural phrasing: "produce a receipt that this is in compliance", "give me an attestation that the cluster matches Git", "I need a verifiable record for the audit trail", "build a receipt verifying no manual edits since deploy", "verify deploy/api against source-truth and save the artifact", "validate this receipt has not been tampered with", "show me what receipts we have", "is this receipt tampered with?", "attach evidence to my CI gate". Load whenever intent is receipt / attestation / evidence-artifact / tamper-evident-record / verified-record / audit-trail / postmortem-evidence / acceptance-judge-input. Do NOT load for: a live comparison without a persisted artifact (use scout-compare), interpreting a single field's provenance (use scout-attribute), or actually applying a fix (cub-scout never mutates — route to cub / argocd / kubectl with the user driving).
- License 许可
- MIT
- 最近更新
- 2026-11-14
- Stars
- ★ 14
- Forks
- 1
01 前言 Front Matter
- name
- scout-verify
- phase
- verify
- description
- Use when the user wants a TYPED, FINGERPRINTED, IMMUTABLE evidence artifact about a Kubernetes resource — the Verify verb group of cub-scout (the receipt capability shipped in #446). Natural phrasing: "produce a receipt that this is in compliance", "give me an attestation that the cluster matches Git", "I need a verifiable record for the audit trail", "build a receipt verifying no manual edits since deploy", "verify deploy/api against source-truth and save the artifact", "validate this receipt has not been tampered with", "show me what receipts we have", "is this receipt tampered with?", "attach evidence to my CI gate". Load whenever intent is receipt / attestation / evidence-artifact / tamper-evident-record / verified-record / audit-trail / postmortem-evidence / acceptance-judge-input. Do NOT load for: a live comparison without a persisted artifact (use scout-compare), interpreting a single field's provenance (use scout-attribute), or actually applying a fix (cub-scout never mutates — route to cub / argocd / kubectl with the user driving).
- allowed-tools
- Bash(./cub-scout receipt verify *) Bash(cub-scout receipt verify *) Bash(cub scout receipt verify *) Bash(./cub-scout receipt show *) Bash(cub-scout receipt show *) Bash(cub scout receipt show *) Bash(./cub-scout receipt validate *) Bash(cub-scout receipt validate *) Bash(cub scout receipt validate *) Bash(./cub-scout receipt list *) Bash(cub-scout receipt list *) Bash(cub scout receipt list *) Bash(./cub-scout receipt list) Bash(cub-scout receipt list) Bash(cub scout receipt list) Bash(kubectl get *) Bash(kubectl describe *) Bash(kubectl get --show-managed-fields *) Bash(cub space list *) Bash(cub unit get *) Bash(cub unit list *) Bash(cub link get *) Bash(cub link list *) Bash(cub view get *) Bash(cub view list *) Bash(cub unit-event list *) Bash(cub resource list *) Bash(cub release list *) Bash(cub changeset list *) Bash(argocd app get *) Bash(flux get *)
03 SKILL.md 正文
scout-verify
The Verify verb group of cub-scout. Produces typed, fingerprinted, immutable evidence artifacts — receipts — wrapping cub-scout's existing field-level evidence into a verifiable record CI/CD gates, audit trails, postmortems, and acceptance-judge tooling can attach to a decision and later re-check for tampering.
A receipt is a stamped, hand-offable record of one verification: an in-toto Statement v1 envelope around a verdict, evidence, omissions, and optional upstream receipt references. Its proof is the verifiable integrity property created by the fingerprint: SHA-256 over RFC 8785 canonical JSON of the full Statement, with only
predicate.fingerprintremoved before hashing. Any third party can recompute that fingerprint to confirm the receipt has not been edited since it was stamped. That is tamper-evidence, not producer authentication or formal proof of truth. A receipt without proof is a claim; a receipt with proof is evidence.
Receipts are HISTORICAL records. Updates produce new receipts; old ones never mutate.
When to use
Explicit phrasings:
- "Produce a receipt that deploy/api is in compliance"
- "Give me a verifiable attestation that the cluster matches Git"
- "I need an evidence artifact for the audit trail"
- "Build a receipt verifying no manual edits since the freeze started"
- "Verify deploy/api against source-truth and save the artifact"
- "Validate this receipt has not been tampered with"
- "List the receipts I've generated locally"
- "Show me yesterday's receipts where the verdict was BLOCK"
- "Attach typed evidence to my CI gate / promotion gate / release ticket"
- "Keep the exact delivery/status feedback snapshot for audit"
Implicit intents:
- The user wants persistence of an evidence snapshot, not just an ephemeral comparison
- The user is gating CI / promotion / acceptance on a verdict
- The user needs to show later exactly what evidence was attached to a decision, with tamper-evidence (forensic / audit / postmortem)
- The user is integrating with Pilot or a similar acceptance kernel that consumes receipt-shaped evidence
- The user wants a tamper-evident artifact, not a log line
Do not load for
- Live comparison without a persisted artifact —
scout-compareis faster and the right shape - Interpreting why a single field is wrong (which controller, which file) —
scout-attribute - Inventory / status / "what's running" —
scout-observe - Forcing an apply / sync / patch — cub-scout cannot. Receipts emit; they never act.
Standalone vs connected
- Standalone (cluster only):
receipt verify --predicate applied-matches-specand--predicate no-manual-edits-sincework without ConfigHub. The receipt recordsOmissionConfigHubUnitSubjectto flag the missing connected-mode evidence. - Connected (cluster +
cub auth login):--predicate source-truth-pass --strategy <name>becomes available. Connected mode also adds theconfighub-unit://subject to every receipt when unit identity is available, anchoring it to the unit revision in addition to the live K8s digest. Single-resourcereceipt verify --with-confighubcan attach object-correlated delivery evidence underpredicate.evidence.deliveryEvidence; this is supporting evidence and does not change predicate verdict semantics. - Offline (file only):
receipt show/receipt validate/receipt listall work on on-disk artifacts with no cluster and no ConfigHub. Useful in CI containers that received the receipt as an artifact from an upstream job.
Tool boundary
- Allowed (read-only): the four receipt verbs (
verify/show/validate/list);kubectl get/describe,kubectl get --show-managed-fields(for inspecting whatno-manual-edits-sincesaw);cub <entity> get / listfor the entities named in allowed-tools (connected);argocd app get,flux get(when building source-truth-pass evidence). - Not allowed:
kubectl apply/edit/patch/delete,argocd app sync(as mutation),flux reconcile --with-source,cub * create/update/delete. Receipts are evidence, never recommendations to mutate.FilterNextSteps(inpkg/agent/receipt_predicates.go) rejects mutatingactionType/nextCommandat receipt-emit time as defense in depth. TestReceiptPackageReadOnlyClient: the static guard incmd/cub-scout/receipt_readonly_test.gogreps everyreceipt*.gosource file and fails the build if any mutating K8s client method appears. Receipts are categorically read-only.
The verb menu
| Question | Verb | Notes |
|---|---|---|
| "Produce a receipt about this resource" | cub-scout receipt verify <kind>/<name> -n <ns> |
Auto-detects the predicate from owner + signals. Defaults to applied-matches-spec for Argo/Flux/ConfigHub-owned resources with a resolved git anchor. |
| "Preserve delivery/status feedback" | cub-scout receipt verify <kind>/<name> -n <ns> --with-confighub --confighub-space <space> |
Single-resource only; freezes object-correlated deliveryEvidence inside the fingerprinted receipt. |
| "Render a saved receipt" | cub-scout receipt show <path> |
ASCII or JSON. Does NOT verify the fingerprint — works on tampered receipts for forensic inspection. |
| "Has this receipt been tampered with?" | cub-scout receipt validate <path> |
Recomputes the fingerprint and compares. Exit 0 OK / 1 mismatch / 2 I/O. JSON output for CI. |
| "What receipts do I have locally, and are TTL-backed ones still fresh?" | cub-scout receipt list --format json |
Walks $CUB_SCOUT_RECEIPTS_DIR → $XDG_DATA_HOME/cub-scout/receipts → $HOME/.local/share/cub-scout/receipts. Newest first, with freshness.status as fresh, stale, not-declared, or invalid. |
The predicates
cub-scout v1 ships three predicates. Each maps a required input signal to a receipt-level verdict:
| Predicate | Required signal | Verdict logic |
|---|---|---|
applied-matches-spec |
Argo/Flux/ConfigHub owner + controller-resolved git anchor | PASS on controller-drift cause; BLOCK on manual-edit cause or anchor mismatch; INCONCLUSIVE on missing anchor or unknown cause. |
source-truth-pass |
--strategy <name> (one of 9) + connected-mode ConfigHub auth |
Mirrors compare source-truth Status → Verdict. Strategy mismatch between caller and evidence → BLOCK. |
no-manual-edits-since |
--since <RFC3339> cutoff |
PASS when no kubectl-* writer touched managedFields after the cutoff. BLOCK on any late interactive write. INCONCLUSIVE on missing managedFields or nil-Time entries (parse-don't-guess). |
cub-scout NEVER infers a strategy or a cutoff. source-truth-pass requires --strategy; no-manual-edits-since requires --since. Pass them or the CLI errors upfront.
Verdicts
Every receipt carries one of four:
| Verdict | Meaning |
|---|---|
PASS |
Evidence supports the claim |
WATCH |
Evidence is ambiguous; situation needs monitoring |
BLOCK |
Evidence contradicts the claim |
INCONCLUSIVE |
Evidence missing or unavailable; always carries one or more omissions[] entries |
INCONCLUSIVE is not failure — it's an honest "I don't have enough to claim PASS." Pilot and similar acceptance kernels treat it as ASK (need human or richer evidence).
The loop
- Pick the predicate. Most users mean
applied-matches-spec(default for Argo/Flux/ConfigHub-owned resources with a resolved anchor). If the user mentions a delivery strategy, they wantsource-truth-pass. If they mention a freeze window or cutoff timestamp, they wantno-manual-edits-since. - Decide standalone vs connected. Receipts work in both modes; connected mode adds the
confighub-unit://subject + ConfigHub-side evidence. Source-truth-pass requires connected mode. - Invoke verify. Use
--format jsonfor CI / agent consumption. Use--saveto land the artifact in the local store (immutable; refuses overwrite). - Read the verdict + omissions. The verdict is the headline;
omissions[]is the "what I deliberately did not claim" list. Empty omissions = comprehensive coverage. Non-empty = honest gaps. - Persist or attach.
--out <path>writes a specific file;--savewrites into the store under the canonical name. CI gates that need to attach the artifact to a build record use--out. - Hand off. If the verdict is BLOCK and the user wants to act, refuse to mutate. Point them at the appropriate
cubskill (for ConfigHub state changes), atkubectl get --show-managed-fields(to investigate a manual-edit BLOCK), or at the original-author path (commit the change back to git).
Worked examples
A: applied-matches-spec, standalone
The default path for an Argo-owned Deployment. Works without ConfigHub auth.
$ cub-scout receipt verify deploy/api -n prod
Receipt: applied-matches-spec
Verdict: PASS
Claim: applied matches spec at apps/prod/api
Scope: Deployment/api in prod
By: cub-scout v2.3.0 at 2026-05-22T10:30:00Z
Spec: https://github.com/org/platform-config @abc123def456 path=apps/prod/api
Subjects
- k8s-live://apps/v1/Deployment/prod/api sha256:595f08ae073d…
Evidence (attribution)
cause: controller-drift
managerHint: argocd-controller
gitSource: https://github.com/org/platform-config @abc123def456 path=apps/prod/api
Omissions (deliberate non-claims)
- confighub-unit-subject — standalone-mode build; no ConfigHub auth available to fetch unit subject [info]
Next steps (read-only)
- [read-only] controller is reconciling; spec anchor matches the resolved git source
→ cub-scout explain
Fingerprint: sha256:252ef3104d0a3cc8ac62e7bde40cf6174b6f045d8ed2b97c6512781d8cb690f4
Save it to disk for a build record:
$ cub-scout receipt verify deploy/api -n prod --format json --out api-prod.receipt.json
Or land it in the local store for casual accumulation:
$ cub-scout receipt verify deploy/api -n prod --save
saved: /home/user/.local/share/cub-scout/receipts/2026-05-22T10-30-00Z__applied-matches-spec__Deployment-api__252ef3104d0a.receipt.json
B: source-truth-pass, declared strategy (connected mode)
$ cub-scout receipt verify deploy/api -n prod --strategy git-argo --format json
{
"_type": "https://in-toto.io/Statement/v1",
"subject": [
{"name": "k8s-live://apps/v1/Deployment/prod/api", "digest": {"sha256": "..."}},
{"name": "confighub-unit://payments-api@rev=42", "digest": {"sha256": "..."}}
],
"predicateType": "https://cub-scout.dev/receipt/v1",
"predicate": {
"predicateName": "source-truth-pass",
"verdict": "PASS",
"evidence": {
"sourceTruth": {
"declared_strategy": "Git -> Argo -> Kubernetes",
"status": "PASS",
"source_truth": "AGREED",
"surfaces": { ... }
}
},
"omissions": [],
"fingerprint": "sha256:..."
}
}
Strategy mismatch is BLOCK — never silently honor the caller's strategy over what the evidence records:
$ cub-scout receipt verify deploy/api -n prod --strategy git-argo
# ... evidence carries confighub-oci-argo, not git-argo ...
Verdict: BLOCK
Omissions
- strategy-mismatch — receipt was asked to verify under strategy "git-argo" but source-truth evidence carries "ConfigHub -> OCI -> Argo -> Kubernetes"
C: no-manual-edits-since freeze gate (standalone)
$ cub-scout receipt verify deploy/api -n prod --since 2026-05-22T00:00:00Z --save
saved: /home/user/.local/share/cub-scout/receipts/2026-05-22T10-30-00Z__no-manual-edits-since__Deployment-api__abc123.receipt.json
$ cub-scout receipt show ~/.local/share/cub-scout/receipts/2026-05-22T10-30-00Z__no-manual-edits-since__Deployment-api__abc123.receipt.json
Receipt: no-manual-edits-since
Verdict: PASS
Claim: no manual edits to Deployment/api in prod since 2026-05-22T00:00:00Z
A late kubectl edit produces BLOCK and names the offending writer:
Verdict: BLOCK
Next steps (read-only)
- [read-only] interactive writer wrote managedFields after the cutoff (2026-05-22T00:00:00Z): kubectl-edit@2026-05-22T12:00:00Z — investigate the unplanned edit before any apply
→ kubectl get --show-managed-fields
D: validate + list
$ cub-scout receipt validate ./api-prod.receipt.json
Fingerprint OK: ./api-prod.receipt.json
sha256:252ef3104d0a3cc8ac62e7bde40cf6174b6f045d8ed2b97c6512781d8cb690f4
$ cub-scout receipt list
Store: /home/user/.local/share/cub-scout/receipts
VERDICT PREDICATE SCOPE VERIFIED-AT PATH
PASS applied-matches-spec Deployment/api in prod 2026-05-22T10:30:00Z 2026-05-22T10-30-00Z__applied-matches-spec__Deployment-api__252ef3104d0a.receipt.json
BLOCK no-manual-edits-since Deployment/api in prod 2026-05-22T08:00:00Z 2026-05-22T08-00-00Z__no-manual-edits-since__Deployment-api__abc123.receipt.json
JSON list output for CI consumption (filter by verdict):
$ cub-scout receipt list --format json | jq '.[] | select(.verdict == "BLOCK")'
Output evidence
What every receipt carries (the structured surface a downstream consumer pattern-matches on):
| Field | Meaning |
|---|---|
predicate.predicateName |
One of applied-matches-spec / source-truth-pass / no-manual-edits-since |
predicate.verdict |
One of PASS / WATCH / BLOCK / INCONCLUSIVE |
predicate.scope |
kind / name / namespace / cluster |
predicate.verifier |
{tool, version} — always cub-scout plus the build tag |
predicate.verifiedAt |
RFC 3339 timestamp |
predicate.spec.anchor |
Git repo + revision + path (applied-matches-spec only) |
predicate.evidence.attribution |
cause / managerHint / gitSource — cub-scout's existing attribution layer |
predicate.evidence.sourceTruth |
Source-truth derivation surfaces (source-truth-pass only) |
predicate.omissions[] |
Structured list of what the receipt deliberately does NOT claim — empty array means comprehensive coverage |
predicate.nextSteps[] |
Read-only follow-up hints (mutating verbs filtered at emit time) |
predicate.fingerprint |
sha256: SHA-256 over RFC 8785 canonical JSON of the full Statement minus only this field |
Storage convention
The local receipt store is a flat directory of *.receipt.json files keyed by a deterministic sortable name:
<verifiedAt-rfc3339-safe>__<predicate>__<kind>-<name>__<short-fingerprint>.receipt.json
Resolved in priority order:
--save-dir <path>on verify,--dir <path>on list (explicit override)$CUB_SCOUT_RECEIPTS_DIRenv var$XDG_DATA_HOME/cub-scout/receipts$HOME/.local/share/cub-scout/receipts
The store is immutable: re-running verify on the same resource at the same instant with the same fingerprint produces the same canonical filename → "already saved" warning and exit 0. The on-disk artifact never changes.
v2 surface (CI / agent shaped)
Three v2 extensions layer on top of the v1 envelope without changing the wire format:
--fail-on <verdict-list>onreceipt verify(#451) — exit non-zero (code 2) when the verdict matches. AcceptsWATCH,BLOCK,INCONCLUSIVE(comma-separated) or the sugarany-non-pass. The receipt is still printed / saved / written to--out— the gate fires AFTER the artifact is durable.--input-attestation <path>chained receipts (#448chained half) — repeatable; each referenced receipt is loaded + fingerprint-verified + attached to the new receipt'sinputAttestations[]. Tampered references refused at chain-construction time. The downstream fingerprint covers the field by construction.cub-scout watch --emit-receipt-on <event-types>/cub-scout bot --emit-receipt-on <event-types>(#449) — attaches a receipt to each matching event payload inline (JSONL or webhook). All four known event types build receipts:drift.detected,ownership.changed,resource.discovered, andscan.finding;--emit-receipt-batch-capbounds burst volume. Failures are non-fatal.
# CI gate
./cub-scout receipt verify deploy/api -n prod --fail-on any-non-pass
# Chain a per-resource receipt with an upstream "release gate passed" one
./cub-scout receipt verify deploy/api -n prod \
--input-attestation ./release-gate.receipt.json \
--save
# Streaming acceptance: each drift event becomes a fingerprinted receipt
./cub-scout watch -n prod \
--output-file ./acceptance.jsonl \
--emit-receipt-on drift.detected,ownership.changed
Not yet in cub-scout
Future directions worth flagging:
- Cryptographic signing as a hardening layer on top of fingerprint-only — DSSE wrapped in a Sigstore Bundle (cosign keyless + ed25519 fallback) is one candidate design; the wire format is intentionally additive-friendly so signatures can land without an envelope change
Shipping releases use fingerprint-only integrity; future hardening is honest about what's not yet there — the contract is in docs/reference/json-contracts.md § Receipt Contract.
References
- Terminology:
docs/concepts/receipts-and-proofs.md— what "receipt" and "proof" mean, vs log / journal / record / ledger / provenance - Contract:
docs/reference/json-contracts.md§ Receipt Contract - Locked design:
docs/proposals/receipts-way-forward.md - Examples:
examples/receipts/— 8 canonical receipts across the three predicates, generated deterministically bytools/gen-receipt-examples - Implementation:
pkg/agent/receipt*.go,cmd/cub-scout/receipt*.go - Read-only triad:
scout-attribute(companion evidence surface),scout-compare(live comparison sibling)
04 同仓库更多 Skills
triage-unhealthy-workload
Use when the user is responding to a broken Kubernetes workload UNDER TIME PRESSURE — pager-going-off, CI-red, "prod is down" framing. Natural phrasing: "deploy/api is CrashLoopBackOff, what now?", "the rollout is stuck, help", "this pod won't start", "pager fired on payments", "everything is red in argocd", "what should I check first?", "give me a triage plan for this workload". Composes doctor → explain → trace into a tight ~30-second loop the operator can run in a pager-acknowledged context. Do NOT load for: a planned investigation without urgency (use scout-diagnose directly), a drift question (use investigate-drift), or anything mutating (cub-scout never mutates — route to kubectl with the user driving).
scout-observe
Use when the user wants to SEE what is running in a Kubernetes cluster, who owns it, and how it is structured — the read-only Observe verb group of cub-scout. Natural phrasing: "what is running in my cluster?", "give me a map of resources", "who owns this Deployment?", "trace this back to its source", "show me the ownership tree", "scan this cluster for risk", "dump the cluster as JSON", "stream cluster events", "run cub-scout as a bot", "what is the connection status?", "is this cluster healthy?". Load when intent is observe / inventory / map / show / list / trace / scan / dump / stream / bot / health-check over a Kubernetes cluster. Do NOT load for: explaining WHY something is broken (use scout-diagnose), comparing cluster state to intended state (use scout-compare), provenance of individual field values (use scout-attribute), or any action that mutates the cluster (cub-scout never mutates — route to cub or kubectl with the user driving).
scout-mcp
Use when the user wants to expose cub-scout to an AI agent over MCP, wants a deterministic AI-ready snapshot of cluster context, or wants cub-scout running as a read-only event bot — the Integrate verb group. Natural phrasing: "start the MCP server", "expose cub-scout to Claude / Codex / my agent", "give me an AI-ready context pack of this cluster", "set up the MCP gateway", "what MCP tools does cub-scout expose?", "run cub-scout as a bot", "produce JSON context for an LLM to reason about this cluster". Load whenever intent is mcp / mcp-gateway / mcp-serve / context-pack / bot / agent-context / ai-snapshot / llm-context / model-context-protocol. Do NOT load for: actually running a non-integrate verb (those are scout-observe / scout-diagnose / scout-compare / scout-attribute / scout-ingest / scout-govern / scout-verify), or `cub` MCP integration (that's a separate tool surface).
scout-ingest
Use when the user wants to ADOPT existing Kubernetes / GitOps workload structure into ConfigHub after observing the live cluster — the adoption/import verb group of cub-scout. Natural phrasing: "discover workloads in this cluster and propose ConfigHub units", "show me the import proposal before I apply", "import this Argo Application set", "bring my Flux Kustomizations into ConfigHub", "preview what would land in ConfigHub if I imported this repo", "parse my git repo as a ConfigHub import bundle", "import a cluster aggregator", "what would --git-path produce for this repo?". Load whenever intent is adopt / import / ingest / preview / propose / parse-repo / discovery / aggregator / bring-into-confighub / what-would-confighub-see. Do NOT load for: questions about who changed a resource, whether it was edited by hand or drifted (use scout-attribute or investigate-drift); reading an exported `kubectl get -o yaml` dump to answer a question about the cluster (that is not an import); basic live-cluster inventory (use scout-observe), troubleshooting (use scout-diagnose), comparing live state to ConfigHub (use scout-compare), or the actual write to ConfigHub via `cub variant upload` (that is `cub`, not cub-scout — route to cub skills). Important: `cub-scout import apply` IS the mutating write into ConfigHub — this skill teaches the read-only preview path and explicitly refuses to invoke `import apply` itself.
scout-govern
Use when the user wants to consume CONNECTED ConfigHub governance signals from cub-scout — the Govern verb group. Natural phrasing: "show me the ChangeSet history for this unit", "what is the blast radius if I change this unit?", "which clusters in my fleet are outliers?", "show me yesterday's connected summary", "render this view across the fleet", "audit who changed this", "where did the last apply come from?", "list ConfigHub bundles I have", "show me the catalog of past snapshots". Load whenever intent is history / impact / blast-radius / fleet-outliers / summary / view / audit / bundle / catalog / connected-context. Do NOT load for: live cluster comparison (use scout-compare), receipts (use scout-verify), inventory of running pods (use scout-observe), or any mutation via cub. Most of this skill requires `cub auth login` — say so upfront.
scout-diagnose
Use when the user wants cub-scout to INTERPRET what it sees and suggest a next step — the Diagnose verb group. Natural phrasing: "explain this Deployment", "why is this broken?", "what should I do about this?", "is this drift or just slow sync?", "what does this error mean?", "is there a known pattern for this?", "is my GitOps pipeline healthy?", "what events are firing on this Pod?", "give me a suggested remedy for this finding". Load whenever intent is explain / why / what-does-it-mean / what-should-I-do / interpret / diagnose / recommend / suggest-fix over a Kubernetes cluster or a scan finding. Do NOT load for: pure cluster inventory (use scout-observe), comparing intended vs running state at the field level (use scout-compare), field-level provenance (use scout-attribute), or actually applying a fix (cub-scout never mutates — route to cub or kubectl with the user driving).