@b00dea/cockpit 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +474 -0
- package/LICENSE +21 -0
- package/README.md +25 -2
- package/bin/cockpit.mjs +33 -0
- package/cockpit.schema.json +2644 -0
- package/dist/autonomy.d.ts +45 -0
- package/dist/autonomy.js +173 -0
- package/dist/bounded-read.d.ts +14 -0
- package/dist/bounded-read.js +42 -0
- package/dist/browser/commands.d.ts +117 -0
- package/dist/browser/commands.js +453 -0
- package/dist/browser/package-paths.d.ts +1 -0
- package/dist/browser/package-paths.js +6 -0
- package/dist/browser/proxy.d.ts +22 -0
- package/dist/browser/proxy.js +37 -0
- package/dist/browser/runtime.d.ts +118 -0
- package/dist/browser/runtime.js +186 -0
- package/dist/browser/surfaces.d.ts +141 -0
- package/dist/browser/surfaces.js +561 -0
- package/dist/browser/ui-gate.d.ts +15 -0
- package/dist/browser/ui-gate.js +18 -0
- package/dist/canonical-json.d.ts +2 -0
- package/dist/canonical-json.js +5 -0
- package/dist/cli-guard.d.ts +5 -0
- package/dist/cli-guard.js +71 -0
- package/dist/cli-main.d.ts +176 -0
- package/dist/cli-main.js +1584 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +16 -0
- package/dist/command-table.d.ts +121 -0
- package/dist/command-table.js +664 -0
- package/dist/config/load.d.ts +183 -0
- package/dist/config/load.js +367 -0
- package/dist/config/sibling-toml.d.ts +48 -0
- package/dist/config/sibling-toml.js +160 -0
- package/dist/config/surface-tools-toml.d.ts +9 -0
- package/dist/config/surface-tools-toml.js +37 -0
- package/dist/config/unconfirmed-toml.d.ts +9 -0
- package/dist/config/unconfirmed-toml.js +29 -0
- package/dist/config/verified-write.d.ts +43 -0
- package/dist/config/verified-write.js +89 -0
- package/dist/diagnostics.d.ts +26 -0
- package/dist/diagnostics.js +344 -0
- package/dist/docs/check.d.ts +16 -0
- package/dist/docs/check.js +197 -0
- package/dist/docs/decision-record.d.ts +34 -0
- package/dist/docs/decision-record.js +135 -0
- package/dist/docs/decisions.d.ts +16 -0
- package/dist/docs/decisions.js +103 -0
- package/dist/docs/markdown.d.ts +36 -0
- package/dist/docs/markdown.js +88 -0
- package/dist/docs/references.d.ts +32 -0
- package/dist/docs/references.js +148 -0
- package/dist/emit.d.ts +22 -0
- package/dist/emit.js +43 -0
- package/dist/entrypoint-kinds.d.ts +3 -0
- package/dist/entrypoint-kinds.js +11 -0
- package/dist/environment/application/confirm.d.ts +35 -0
- package/dist/environment/application/confirm.js +122 -0
- package/dist/environment/application/destructive.d.ts +6 -0
- package/dist/environment/application/destructive.js +429 -0
- package/dist/environment/application/doctor.d.ts +94 -0
- package/dist/environment/application/doctor.js +247 -0
- package/dist/environment/application/guard.d.ts +49 -0
- package/dist/environment/application/guard.js +677 -0
- package/dist/environment/application/health.d.ts +143 -0
- package/dist/environment/application/health.js +385 -0
- package/dist/environment/application/lifecycle-context.d.ts +235 -0
- package/dist/environment/application/lifecycle-context.js +154 -0
- package/dist/environment/application/lifecycle-state.d.ts +25 -0
- package/dist/environment/application/lifecycle-state.js +202 -0
- package/dist/environment/application/lifecycle.d.ts +18 -0
- package/dist/environment/application/lifecycle.js +737 -0
- package/dist/environment/application/logs.d.ts +45 -0
- package/dist/environment/application/logs.js +127 -0
- package/dist/environment/application/services.d.ts +60 -0
- package/dist/environment/application/services.js +89 -0
- package/dist/environment/application/setup.d.ts +129 -0
- package/dist/environment/application/setup.js +741 -0
- package/dist/environment/application/shared.d.ts +11 -0
- package/dist/environment/application/shared.js +61 -0
- package/dist/environment/application/siblings.d.ts +43 -0
- package/dist/environment/application/siblings.js +269 -0
- package/dist/environment/claims.d.ts +389 -0
- package/dist/environment/claims.js +1701 -0
- package/dist/environment/codex-hook-trust.d.ts +11 -0
- package/dist/environment/codex-hook-trust.js +185 -0
- package/dist/environment/compose-environment.d.ts +1 -0
- package/dist/environment/compose-environment.js +6 -0
- package/dist/environment/compose-ownership.d.ts +21 -0
- package/dist/environment/compose-ownership.js +117 -0
- package/dist/environment/compose-topology.d.ts +125 -0
- package/dist/environment/compose-topology.js +490 -0
- package/dist/environment/contract.d.ts +522 -0
- package/dist/environment/contract.js +794 -0
- package/dist/environment/declaration.d.ts +14 -0
- package/dist/environment/declaration.js +39 -0
- package/dist/environment/destructive-composition.d.ts +29 -0
- package/dist/environment/destructive-composition.js +333 -0
- package/dist/environment/docker-daemon.d.ts +30 -0
- package/dist/environment/docker-daemon.js +78 -0
- package/dist/environment/docker-endpoint.d.ts +10 -0
- package/dist/environment/docker-endpoint.js +19 -0
- package/dist/environment/env-schema-observation.d.ts +46 -0
- package/dist/environment/env-schema-observation.js +241 -0
- package/dist/environment/evidence.d.ts +136 -0
- package/dist/environment/evidence.js +437 -0
- package/dist/environment/executable.d.ts +38 -0
- package/dist/environment/executable.js +190 -0
- package/dist/environment/generated-application/authorities.d.ts +5 -0
- package/dist/environment/generated-application/authorities.js +61 -0
- package/dist/environment/generated-application/bootstrap-skill.d.ts +16 -0
- package/dist/environment/generated-application/bootstrap-skill.js +328 -0
- package/dist/environment/generated-application/check.d.ts +13 -0
- package/dist/environment/generated-application/check.js +191 -0
- package/dist/environment/generated-application/custom-surface.d.ts +26 -0
- package/dist/environment/generated-application/custom-surface.js +289 -0
- package/dist/environment/generated-application/prepare.d.ts +29 -0
- package/dist/environment/generated-application/prepare.js +278 -0
- package/dist/environment/generated-application/publication.d.ts +33 -0
- package/dist/environment/generated-application/publication.js +547 -0
- package/dist/environment/generated-application/shared.d.ts +492 -0
- package/dist/environment/generated-application/shared.js +354 -0
- package/dist/environment/generated-application/surface-observation.d.ts +4 -0
- package/dist/environment/generated-application/surface-observation.js +69 -0
- package/dist/environment/generated-application/surface-outputs.d.ts +71 -0
- package/dist/environment/generated-application/surface-outputs.js +400 -0
- package/dist/environment/generated-application/surfaces.d.ts +3 -0
- package/dist/environment/generated-application/surfaces.js +704 -0
- package/dist/environment/generated-application/sync.d.ts +6 -0
- package/dist/environment/generated-application/sync.js +124 -0
- package/dist/environment/git-observation.d.ts +202 -0
- package/dist/environment/git-observation.js +553 -0
- package/dist/environment/health-composition.d.ts +12 -0
- package/dist/environment/health-composition.js +645 -0
- package/dist/environment/host-observation.d.ts +56 -0
- package/dist/environment/host-observation.js +52 -0
- package/dist/environment/identity.d.ts +48 -0
- package/dist/environment/identity.js +85 -0
- package/dist/environment/init-application.d.ts +333 -0
- package/dist/environment/init-application.js +726 -0
- package/dist/environment/install-policy-observation.d.ts +71 -0
- package/dist/environment/install-policy-observation.js +284 -0
- package/dist/environment/install-policy.d.ts +48 -0
- package/dist/environment/install-policy.js +96 -0
- package/dist/environment/instance.d.ts +33 -0
- package/dist/environment/instance.js +122 -0
- package/dist/environment/instruction-pointer.d.ts +19 -0
- package/dist/environment/instruction-pointer.js +144 -0
- package/dist/environment/lifecycle-composition.d.ts +31 -0
- package/dist/environment/lifecycle-composition.js +742 -0
- package/dist/environment/lifecycle-stage.d.ts +120 -0
- package/dist/environment/lifecycle-stage.js +408 -0
- package/dist/environment/lifecycle.d.ts +75 -0
- package/dist/environment/lifecycle.js +354 -0
- package/dist/environment/logs.d.ts +132 -0
- package/dist/environment/logs.js +519 -0
- package/dist/environment/map-limit.d.ts +2 -0
- package/dist/environment/map-limit.js +13 -0
- package/dist/environment/mcp-observation.d.ts +9 -0
- package/dist/environment/mcp-observation.js +46 -0
- package/dist/environment/observations.d.ts +46 -0
- package/dist/environment/observations.js +346 -0
- package/dist/environment/operator-application.d.ts +79 -0
- package/dist/environment/operator-application.js +197 -0
- package/dist/environment/ports.d.ts +182 -0
- package/dist/environment/ports.js +1205 -0
- package/dist/environment/posture-observation.d.ts +68 -0
- package/dist/environment/posture-observation.js +253 -0
- package/dist/environment/presence.d.ts +4 -0
- package/dist/environment/presence.js +26 -0
- package/dist/environment/read-composition.d.ts +32 -0
- package/dist/environment/read-composition.js +397 -0
- package/dist/environment/readiness-composition.d.ts +57 -0
- package/dist/environment/readiness-composition.js +151 -0
- package/dist/environment/reclaim.d.ts +370 -0
- package/dist/environment/reclaim.js +1940 -0
- package/dist/environment/repository-identity.d.ts +13 -0
- package/dist/environment/repository-identity.js +108 -0
- package/dist/environment/runtime-measurement-record.d.ts +38 -0
- package/dist/environment/runtime-measurement-record.js +111 -0
- package/dist/environment/runtime-measurement.d.ts +27 -0
- package/dist/environment/runtime-measurement.js +224 -0
- package/dist/environment/runtime-probe-residue.d.ts +43 -0
- package/dist/environment/runtime-probe-residue.js +148 -0
- package/dist/environment/runtime-probe.d.ts +72 -0
- package/dist/environment/runtime-probe.js +725 -0
- package/dist/environment/runtime.d.ts +551 -0
- package/dist/environment/runtime.js +2405 -0
- package/dist/environment/seed.d.ts +16 -0
- package/dist/environment/seed.js +43 -0
- package/dist/environment/selftest-application.d.ts +86 -0
- package/dist/environment/selftest-application.js +713 -0
- package/dist/environment/sensitive.d.ts +3 -0
- package/dist/environment/sensitive.js +48 -0
- package/dist/environment/served-checkout-grants.d.ts +53 -0
- package/dist/environment/served-checkout-grants.js +182 -0
- package/dist/environment/setup-observation.d.ts +62 -0
- package/dist/environment/setup-observation.js +1473 -0
- package/dist/environment/setup.d.ts +43 -0
- package/dist/environment/setup.js +176 -0
- package/dist/environment/sibling-checkouts.d.ts +119 -0
- package/dist/environment/sibling-checkouts.js +254 -0
- package/dist/environment/sibling-instructions.d.ts +33 -0
- package/dist/environment/sibling-instructions.js +224 -0
- package/dist/environment/sibling-observation.d.ts +27 -0
- package/dist/environment/sibling-observation.js +45 -0
- package/dist/environment/sibling-pull.d.ts +23 -0
- package/dist/environment/sibling-pull.js +95 -0
- package/dist/environment/sibling-registration.d.ts +45 -0
- package/dist/environment/sibling-registration.js +538 -0
- package/dist/environment/stack-inputs.d.ts +18 -0
- package/dist/environment/stack-inputs.js +210 -0
- package/dist/environment/stack-inventory-prune.d.ts +31 -0
- package/dist/environment/stack-inventory-prune.js +129 -0
- package/dist/environment/stack-inventory-report.d.ts +44 -0
- package/dist/environment/stack-inventory-report.js +78 -0
- package/dist/environment/stack-inventory.d.ts +94 -0
- package/dist/environment/stack-inventory.js +418 -0
- package/dist/environment/state.d.ts +410 -0
- package/dist/environment/state.js +2153 -0
- package/dist/environment/templates.d.ts +140 -0
- package/dist/environment/templates.js +685 -0
- package/dist/environment/tool-registration.d.ts +9 -0
- package/dist/environment/tool-registration.js +92 -0
- package/dist/environment/upgrade-application.d.ts +19 -0
- package/dist/environment/upgrade-application.js +175 -0
- package/dist/environment-exec/execute.d.ts +105 -0
- package/dist/environment-exec/execute.js +1179 -0
- package/dist/environment-exec/libexec-program.d.ts +6 -0
- package/dist/environment-exec/libexec-program.js +22 -0
- package/dist/environment-exec/verified-digest.d.ts +4 -0
- package/dist/environment-exec/verified-digest.js +16 -0
- package/dist/exact-keys.d.ts +7 -0
- package/dist/exact-keys.js +15 -0
- package/dist/fix-catalogue.d.ts +32 -0
- package/dist/fix-catalogue.js +60 -0
- package/dist/freshness.d.ts +29 -0
- package/dist/freshness.js +75 -0
- package/dist/generated-environment/adopt.d.ts +16 -0
- package/dist/generated-environment/adopt.js +271 -0
- package/dist/generated-environment/command.d.ts +47 -0
- package/dist/generated-environment/command.js +75 -0
- package/dist/generated-environment/transaction.d.ts +186 -0
- package/dist/generated-environment/transaction.js +1770 -0
- package/dist/grading/evaluate.d.ts +71 -0
- package/dist/grading/evaluate.js +403 -0
- package/dist/grading/grade.d.ts +33 -0
- package/dist/grading/grade.js +57 -0
- package/dist/guards/answer-confirmation.d.ts +41 -0
- package/dist/guards/answer-confirmation.js +109 -0
- package/dist/guards/evaluator.d.ts +130 -0
- package/dist/guards/evaluator.js +1258 -0
- package/dist/guards/harness-adapter.d.ts +17 -0
- package/dist/guards/harness-adapter.js +57 -0
- package/dist/guards/host.d.ts +8 -0
- package/dist/guards/host.js +10 -0
- package/dist/guards/invocation-parser.d.ts +66 -0
- package/dist/guards/invocation-parser.js +595 -0
- package/dist/guards/local-identity.d.ts +44 -0
- package/dist/guards/local-identity.js +129 -0
- package/dist/guards/policy-change.d.ts +43 -0
- package/dist/guards/policy-change.js +159 -0
- package/dist/guards/policy-pin.d.ts +13 -0
- package/dist/guards/policy-pin.js +177 -0
- package/dist/guards/protected-locations.d.ts +62 -0
- package/dist/guards/protected-locations.js +461 -0
- package/dist/guards/read-only.d.ts +37 -0
- package/dist/guards/read-only.js +315 -0
- package/dist/init/command.d.ts +41 -0
- package/dist/init/command.js +330 -0
- package/dist/init/derive.d.ts +53 -0
- package/dist/init/derive.js +819 -0
- package/dist/init/draft.d.ts +140 -0
- package/dist/init/draft.js +1228 -0
- package/dist/init/render.d.ts +47 -0
- package/dist/init/render.js +104 -0
- package/dist/init/scaffold.d.ts +53 -0
- package/dist/init/scaffold.js +121 -0
- package/dist/invocation.d.ts +13 -0
- package/dist/invocation.js +20 -0
- package/dist/package-metadata.d.ts +9 -0
- package/dist/package-metadata.js +19 -0
- package/dist/readiness.d.ts +53 -0
- package/dist/readiness.js +88 -0
- package/dist/references/named.d.ts +24 -0
- package/dist/references/named.js +27 -0
- package/dist/refusal.d.ts +15 -0
- package/dist/refusal.js +7 -0
- package/dist/registry-derivation.d.ts +31 -0
- package/dist/registry-derivation.js +32 -0
- package/dist/registry-resolve/command.d.ts +47 -0
- package/dist/registry-resolve/command.js +226 -0
- package/dist/registry-resolve/registry.d.ts +68 -0
- package/dist/registry-resolve/registry.js +292 -0
- package/dist/registry-resolve/render-shell.d.ts +18 -0
- package/dist/registry-resolve/render-shell.js +36 -0
- package/dist/repair.d.ts +29 -0
- package/dist/repair.js +8 -0
- package/dist/repository-path.d.ts +9 -0
- package/dist/repository-path.js +16 -0
- package/dist/schema-json.d.ts +1 -0
- package/dist/schema-json.js +177 -0
- package/dist/schema.d.ts +1289 -0
- package/dist/schema.js +985 -0
- package/dist/setup/command.d.ts +4 -0
- package/dist/setup/command.js +4 -0
- package/dist/sha256.d.ts +1 -0
- package/dist/sha256.js +4 -0
- package/dist/surfaces/adoption.d.ts +41 -0
- package/dist/surfaces/adoption.js +217 -0
- package/dist/surfaces/consumer-instructions.d.ts +20 -0
- package/dist/surfaces/consumer-instructions.js +43 -0
- package/dist/surfaces/contract.d.ts +42 -0
- package/dist/surfaces/contract.js +169 -0
- package/dist/surfaces/core-declarations.d.ts +24 -0
- package/dist/surfaces/core-declarations.js +79 -0
- package/dist/surfaces/development-markers.d.ts +1 -0
- package/dist/surfaces/development-markers.js +18 -0
- package/dist/surfaces/generator-adapter.d.ts +71 -0
- package/dist/surfaces/generator-adapter.js +809 -0
- package/dist/surfaces/harness-registry.d.ts +260 -0
- package/dist/surfaces/harness-registry.js +146 -0
- package/dist/surfaces/mcp.d.ts +145 -0
- package/dist/surfaces/mcp.js +349 -0
- package/dist/surfaces/merge.d.ts +30 -0
- package/dist/surfaces/merge.js +105 -0
- package/dist/surfaces/ownership.d.ts +190 -0
- package/dist/surfaces/ownership.js +795 -0
- package/dist/surfaces/projection.d.ts +136 -0
- package/dist/surfaces/projection.js +716 -0
- package/dist/surfaces/render.d.ts +79 -0
- package/dist/surfaces/render.js +636 -0
- package/dist/surfaces/restrictions.d.ts +130 -0
- package/dist/surfaces/restrictions.js +447 -0
- package/dist/surfaces/selftest.d.ts +162 -0
- package/dist/surfaces/selftest.js +393 -0
- package/dist/surfaces/skill-contract.d.ts +85 -0
- package/dist/surfaces/skill-contract.js +449 -0
- package/dist/surfaces/sync.d.ts +57 -0
- package/dist/surfaces/sync.js +164 -0
- package/dist/team-metadata.d.ts +41 -0
- package/dist/team-metadata.js +513 -0
- package/dist/testing/gates.d.ts +91 -0
- package/dist/testing/gates.js +182 -0
- package/dist/testing/hooks.d.ts +59 -0
- package/dist/testing/hooks.js +139 -0
- package/dist/testing/test-protection.d.ts +34 -0
- package/dist/testing/test-protection.js +137 -0
- package/dist/testing/verdict.d.ts +29 -0
- package/dist/testing/verdict.js +62 -0
- package/dist/testing/weakening.d.ts +15 -0
- package/dist/testing/weakening.js +30 -0
- package/dist/work-orders/application-closure.d.ts +7 -0
- package/dist/work-orders/application-closure.js +76 -0
- package/dist/work-orders/application-context.d.ts +162 -0
- package/dist/work-orders/application-context.js +137 -0
- package/dist/work-orders/application-decisions.d.ts +27 -0
- package/dist/work-orders/application-decisions.js +121 -0
- package/dist/work-orders/application-grading.d.ts +11 -0
- package/dist/work-orders/application-grading.js +212 -0
- package/dist/work-orders/application.d.ts +6 -0
- package/dist/work-orders/application.js +223 -0
- package/dist/work-orders/composition.d.ts +101 -0
- package/dist/work-orders/composition.js +1202 -0
- package/dist/work-orders/contract.d.ts +77 -0
- package/dist/work-orders/contract.js +140 -0
- package/dist/work-orders/decisions.d.ts +23 -0
- package/dist/work-orders/decisions.js +55 -0
- package/dist/work-orders/store.d.ts +207 -0
- package/dist/work-orders/store.js +291 -0
- package/docs/README.md +68 -0
- package/docs/architecture.md +136 -0
- package/docs/capability-matrix.md +58 -0
- package/docs/cli-reference.md +807 -0
- package/docs/command-list.md +62 -0
- package/docs/compose-patterns.md +99 -0
- package/docs/concepts.md +173 -0
- package/docs/configuration-essentials.md +177 -0
- package/docs/configuration-reference.md +636 -0
- package/docs/docs-check.md +76 -0
- package/docs/environment.md +948 -0
- package/docs/extending.md +43 -0
- package/docs/faq.md +113 -0
- package/docs/getting-started.md +692 -0
- package/docs/harness-surfaces.md +500 -0
- package/docs/joining-a-team.md +76 -0
- package/docs/release-policy.md +49 -0
- package/docs/safety-and-autonomy.md +463 -0
- package/docs/troubleshooting.md +382 -0
- package/docs/tutorial.md +171 -0
- package/docs/work-and-browser.md +420 -0
- package/libexec/browser-operation.cjs +270 -0
- package/libexec/fence-marker.cjs +101 -0
- package/libexec/fence-marker.d.cts +24 -0
- package/libexec/fenced-group-runner.cjs +77 -0
- package/libexec/fenced-supervisor.cjs +137 -0
- package/libexec/generated-filesystem.cjs +731 -0
- package/libexec/install-filesystem.cjs +225 -0
- package/libexec/rulesync-generator.NOTICE.md +1112 -0
- package/libexec/rulesync-generator.cjs +743 -0
- package/libexec/surface-generator-worker.cjs +266 -0
- package/libexec/surface-output-reader.cjs +99 -0
- package/libexec/surface-scratch-cleanup.cjs +14 -0
- package/libexec/validate-harness-evidence.d.mts +183 -0
- package/libexec/validate-harness-evidence.mjs +1312 -0
- package/package.json +74 -4
- package/surfaces/README.md +33 -0
- package/surfaces/agents/evaluator.agent.md +76 -0
- package/surfaces/guards/bash-guard.sh +48 -0
- package/surfaces/guards/claude.adapter.json +25 -0
- package/surfaces/guards/codex.adapter.json +24 -0
- package/surfaces/guards/opencode.adapter.json +25 -0
- package/surfaces/references/browser.md +63 -0
- package/surfaces/references/test-data-and-personas.md +84 -0
- package/surfaces/references/testing-tiers.md +11 -0
- package/surfaces/skills/cockpit-browser.skill.md +59 -0
- package/surfaces/skills/cockpit-explain.skill.md +32 -0
- package/surfaces/skills/cockpit-fix.skill.md +37 -0
- package/surfaces/skills/cockpit-setup.skill.md +39 -0
- package/surfaces/skills/cockpit-work.skill.md +34 -0
- package/surfaces/skills/collection.json +5 -0
- package/surfaces/skills/procedures/explain.md +66 -0
- package/surfaces/skills/procedures/fix.md +95 -0
- package/surfaces/skills/procedures/setup.md +452 -0
- package/surfaces/skills/procedures/work.md +134 -0
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
# Work, grading, browser and testing
|
|
2
|
+
|
|
3
|
+
This page is for anyone deciding whether a change needs a direct fix or a durable
|
|
4
|
+
[work order](concepts.md#work-order), and then getting it graded, checked in a browser, and proven
|
|
5
|
+
with the right test tier.
|
|
6
|
+
|
|
7
|
+
Each command's `--help` is its current contract. Most changes are fixes: the `cockpit-fix` skill
|
|
8
|
+
proves one with the declared test gate before and after, with no order. Write a work order when the
|
|
9
|
+
result must be held to criteria someone else set, graded by something other than the agent that did
|
|
10
|
+
the work, or carried across sessions. The `cockpit-work` skill walks an agent through the loop below;
|
|
11
|
+
the `cockpit-browser` skill runs the commands in [Browser evidence](#browser-evidence).
|
|
12
|
+
|
|
13
|
+
## Write a work order
|
|
14
|
+
|
|
15
|
+
A work order is `workorders/<id>.md`. Its YAML front-matter is the whole contract cockpit accepts,
|
|
16
|
+
checks and grades; the Markdown body below it is yours, for notes and a plan, and cockpit never reads
|
|
17
|
+
it.
|
|
18
|
+
|
|
19
|
+
```markdown
|
|
20
|
+
---
|
|
21
|
+
id: WO-1
|
|
22
|
+
objective: Signing in with an expired session sends the person back to where they were.
|
|
23
|
+
scope:
|
|
24
|
+
- src/auth/
|
|
25
|
+
- tests/auth/**
|
|
26
|
+
- web:src/routes/login.ts
|
|
27
|
+
depends_on: []
|
|
28
|
+
gates: [unit]
|
|
29
|
+
criteria:
|
|
30
|
+
- id: AC1
|
|
31
|
+
text: After sign-in, a person whose session expired returns to the page they asked for.
|
|
32
|
+
check: { gate: unit, select: "test:returns to the requested page" }
|
|
33
|
+
- id: AC2
|
|
34
|
+
text: The redirect target is never another origin.
|
|
35
|
+
check: [npm, test, --, auth/redirect]
|
|
36
|
+
source: docs/security/redirects.md
|
|
37
|
+
non_goals:
|
|
38
|
+
- Changing how sessions expire.
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
Notes and plan go here.
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
| Field | Meaning |
|
|
45
|
+
| --- | --- |
|
|
46
|
+
| `id` | The file's name without `.md`: letters, digits, `.`, `_` or `-`. |
|
|
47
|
+
| `objective` | One outcome, in a sentence. |
|
|
48
|
+
| `scope` | Paths and globs the work may change. A plain path covers what is below it; `*` stays within a directory and `**` crosses them. `<sibling slug>:path` names a sibling's file. |
|
|
49
|
+
| `depends_on` | Orders that must be done before this one signs off. |
|
|
50
|
+
| `gates` | Declared `[testing]` gates `work check` runs besides the criteria's checks. |
|
|
51
|
+
| `criteria` | One to twelve, each an `id`, a `text` a reviewer cannot read two ways, an optional `check` and an optional `source`. |
|
|
52
|
+
| `check` | `{ gate, select }` runs a declared gate, optionally selected as `test-run --select` takes it; a list is an argv cockpit runs from the cockpit root, without a shell. |
|
|
53
|
+
| `source` | A file the criterion comes from. Its bytes are part of the contract, so a changed source makes the order stale. |
|
|
54
|
+
| `non_goals` | What the order deliberately leaves alone. |
|
|
55
|
+
|
|
56
|
+
One schema validates the front-matter; a refusal names each field it rejects. The digest an acceptance
|
|
57
|
+
binds covers the front-matter, the bytes of every `source`, and the commit each repository stood at
|
|
58
|
+
when the order was accepted. A check is the product's own test command, so it runs like a product test
|
|
59
|
+
stage: from the directory holding `cockpit.toml`, with `PATH` and the same non-secret variables,
|
|
60
|
+
judged by exit status, keeping the end of long output, for at most `work.verification_timeout_seconds`.
|
|
61
|
+
|
|
62
|
+
## Accept, check, grade and close
|
|
63
|
+
|
|
64
|
+
<!-- cockpit:ref command=work status --> <!-- cockpit:ref command=work accept --> <!-- cockpit:ref command=work check --> <!-- cockpit:ref command=work grade --> <!-- cockpit:ref command=work acknowledge --> <!-- cockpit:ref command=work signoff -->
|
|
65
|
+
|
|
66
|
+
```sh
|
|
67
|
+
npx --no cockpit work accept --config cockpit.toml --work-order WO-1
|
|
68
|
+
npx --no cockpit work check --config cockpit.toml --work-order WO-1
|
|
69
|
+
npx --no cockpit work grade --config cockpit.toml --work-order WO-1
|
|
70
|
+
npx --no cockpit work signoff --config cockpit.toml --work-order WO-1
|
|
71
|
+
npx --no cockpit work status --config cockpit.toml
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
An order moves draft → accepted → checked → graded → done. `work status` also shows three states it
|
|
75
|
+
derives: **stale** when the file or a source changed since acceptance, **blocked** while an open
|
|
76
|
+
question waits or the attempt cap is reached, and **draft** before acceptance. `partial` and
|
|
77
|
+
`abandoned` are closures. The work-in-progress cap, `work.wip_cap`, counts accepted orders that are
|
|
78
|
+
not closed, and `work accept` refuses a new one past it. A failed check or grade counts an attempt;
|
|
79
|
+
at `work.attempt_cap` the order is blocked until it is amended or closed, by whoever
|
|
80
|
+
[`[work.gates]`](#who-passes-each-gate) names for `amend` and `signoff`; the refusal names who.
|
|
81
|
+
|
|
82
|
+
- **accept** records the contract. Run it again after editing an accepted order to accept the change
|
|
83
|
+
(an [amendment](#amendments)). The check base stays the commits recorded at first acceptance.
|
|
84
|
+
- **check** runs every criterion's check and the order's gates, in the order the contract lists them.
|
|
85
|
+
- **grade** grades the order the way [`[work] grading`](#how-an-order-earns-done) says, and reports
|
|
86
|
+
every changed file outside `scope` since the base commits under `outOfScope`. Where a model grades,
|
|
87
|
+
each such change is judged by the standing criterion `scope-changes-necessary`; under `checks`
|
|
88
|
+
grading any change outside scope fails the grade. [Weakened tests](#test-protection) are judged the
|
|
89
|
+
same way.
|
|
90
|
+
- **signoff** closes a graded order as done. `--partial --note <what is left>` or `--abandon --note <why>`
|
|
91
|
+
closes any open order without a passing grade. Every closure first needs each
|
|
92
|
+
[decision](#decisions) recorded on the order to be resolved.
|
|
93
|
+
- <!-- cockpit:ref command=work note --> <!-- cockpit:ref command=work answer --> **note** records a note; `--ask` records an open question, which blocks the order until
|
|
94
|
+
`work answer --question <n> --text <answer>` answers it.
|
|
95
|
+
- <!-- cockpit:ref command=work recover --> **recover** inspects the lock a crashed command left on an order, naming its holder and
|
|
96
|
+
what it checked. `--apply`, which an agent may run, removes the lock only once the holder is shown
|
|
97
|
+
gone: the lock records the writer's host and whether it ran in a container, a holder on another host
|
|
98
|
+
or in a container this machine's Docker does not list stays unknown, a container cockpit labels
|
|
99
|
+
counts as gone only when it is stopped, and a holder on this machine is probed by process. When Docker
|
|
100
|
+
is installed but cannot be read, it refuses. What it checked goes into the order's record under
|
|
101
|
+
`recoveries`.
|
|
102
|
+
|
|
103
|
+
<!-- cockpit:ref path=packages/cockpit/src/guards/evaluator.ts --> cockpit keeps what happened in `.cockpit/work-orders/<id>.json`, committed with the work. It
|
|
104
|
+
records who passed each step (`agent`, `person` or `ci`), each check's result, the grade with the
|
|
105
|
+
evaluator that answered and those passed over, notes, and how the order closed. Only cockpit writes
|
|
106
|
+
those records: the guard denies an agent's writes below `.cockpit/work-orders/` as
|
|
107
|
+
[guard controls](safety-and-autonomy.md#configuration-git-and-guard-controls), because a record carries
|
|
108
|
+
no key and one an agent wrote would read as a person's. That holds only for the tool calls the guard
|
|
109
|
+
inspects; a process outside the guard can still replace a record.
|
|
110
|
+
|
|
111
|
+
## Who passes each gate
|
|
112
|
+
|
|
113
|
+
<!-- cockpit:ref schema=work.gates.accept --> `[work.gates]` in `cockpit.toml` says who passes each step: `accept`, `amend` (accepting a changed
|
|
114
|
+
contract), `answer`, `signoff` and `acknowledge` (accepting that an order weakened tests). Every default
|
|
115
|
+
is `agent`.
|
|
116
|
+
|
|
117
|
+
| Value | What happens |
|
|
118
|
+
| --- | --- |
|
|
119
|
+
| `agent` | The command passes the step. |
|
|
120
|
+
| `person` | The command shows what is being decided and its digest, and records the step only after a person types that digest in a terminal with `--interactive`. Without a terminal it refuses with `WORK_PERSON_REQUIRED`. |
|
|
121
|
+
| `ci` | The command records the step as awaiting CI, and it counts once the required `work verify` job passes. |
|
|
122
|
+
|
|
123
|
+
Removing an accepted criterion or gate is never the agent's to certify: under `amend = "agent"` such an
|
|
124
|
+
amendment still needs a person. [Amendments](#amendments) says what happens to the rest.
|
|
125
|
+
|
|
126
|
+
These local gates are best-effort. The guard keeps an agent's tool call from passing `--interactive`,
|
|
127
|
+
and the command needs a terminal on both standard input and standard output, but cockpit cannot tell a
|
|
128
|
+
person from a program driving a terminal. The only enforced human gate is `ci`: a required
|
|
129
|
+
`work verify` job behind a protected environment whose reviewers must approve it before it runs.
|
|
130
|
+
|
|
131
|
+
<!-- cockpit:ref command=work verify --> `work verify` checks every record against its order: an open order whose contract changed since
|
|
132
|
+
acceptance fails, and so does a done order without a passing grade of its accepted contract, and so
|
|
133
|
+
does a [decision record](#decisions) an order cites that is gone or no longer names the order. Run in
|
|
134
|
+
CI (where `CI` is set), it reports the steps gated on `ci` as confirmed; run locally it lists them as
|
|
135
|
+
awaiting CI. A workflow job for it:
|
|
136
|
+
|
|
137
|
+
```yaml
|
|
138
|
+
work-verify:
|
|
139
|
+
runs-on: ubuntu-latest
|
|
140
|
+
environment: work-orders # add required reviewers to this environment
|
|
141
|
+
steps:
|
|
142
|
+
- uses: actions/checkout@v4
|
|
143
|
+
- uses: actions/setup-node@v4
|
|
144
|
+
with: { node-version: 24 }
|
|
145
|
+
- run: npm ci
|
|
146
|
+
- run: npx --no cockpit work verify --config cockpit.toml
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Make the job a required status check on the protected branch, so an order's `ci` steps reach the branch
|
|
150
|
+
only through it.
|
|
151
|
+
|
|
152
|
+
## How an order earns done
|
|
153
|
+
|
|
154
|
+
<!-- cockpit:ref schema=work.grading --> `[work] grading` says what `work grade` does, and the record, `work status` and `doctor` always say
|
|
155
|
+
which way each order closed:
|
|
156
|
+
|
|
157
|
+
| `grading` | `work grade` | Closes as |
|
|
158
|
+
| --- | --- | --- |
|
|
159
|
+
| `independent` (default) | runs the checks, then an evaluator grades each criterion against them and the change | `graded` |
|
|
160
|
+
| `checks` | runs the checks; every criterion needs one, and the grade passes only when cockpit ran each and all passed and nothing changed outside `scope` | `checks-passed` |
|
|
161
|
+
| `self` | runs the checks, then records the agent's `--verdict met` or `unmet` with a `--note` saying what it checked; the verdict covers the standing criteria too, so the note must name each path changed outside `scope` and each flagged test file (or a directory above it), and a failed check still fails it | `self-reported` |
|
|
162
|
+
|
|
163
|
+
The signoff gate applies on top in every mode.
|
|
164
|
+
|
|
165
|
+
Under `independent` and `self` grading cockpit adds standing criteria when they apply, judged with the
|
|
166
|
+
order's own: `scope-changes-necessary` when files changed outside `scope`, `test-changes-justified`
|
|
167
|
+
when [test protection](#test-protection) flags a change, `amendments-hold-bar` when an agent
|
|
168
|
+
[amended](#amendments) the contract, and the [decision and documentation](#decisions) criteria when
|
|
169
|
+
`[docs]` is declared. An order may not name a criterion with one of these ids. Under `checks` no model
|
|
170
|
+
reads the change, so a change outside scope, an unacknowledged weakening and an unjudgeable amendment
|
|
171
|
+
are decided by rule instead.
|
|
172
|
+
|
|
173
|
+
### Amendments
|
|
174
|
+
|
|
175
|
+
Editing an accepted order and running `work accept` again records an amendment in the record's
|
|
176
|
+
`amendments`, with who passed it, what it removed and, under `review`, each part that changed in a way
|
|
177
|
+
that may lower the bar, before and after:
|
|
178
|
+
|
|
179
|
+
| Change | Under `amend = "agent"` |
|
|
180
|
+
| --- | --- |
|
|
181
|
+
| A criterion or gate removed | needs a person, in every grading mode |
|
|
182
|
+
| A criterion rewritten (its text, check or source), `scope` widened | under `independent` and `self`, passes and is judged at the next grade; under `checks`, needs a person |
|
|
183
|
+
| A non-goal dropped or reworded, the objective changed | passes, and is judged at the next grade where a model grades |
|
|
184
|
+
| A criterion or gate added, `scope` narrowed, a non-goal added | passes |
|
|
185
|
+
|
|
186
|
+
The next grade carries `amendments-hold-bar`, with the before and after of every amendment the agent
|
|
187
|
+
made since a person or CI last accepted the contract; under `independent` the evaluator also sees them
|
|
188
|
+
as the change to `workorders/<id>.md`. When it is not met the grade fails, and the next amendment and
|
|
189
|
+
any closure are a person's: revert or rewrite the order, then a person runs `work accept --interactive`. The order
|
|
190
|
+
records the finding, so a later `work check` or grade does not clear it; only an amendment a person or
|
|
191
|
+
CI accepts does.
|
|
192
|
+
|
|
193
|
+
<!-- cockpit:ref command=grade --> For a change that needs no order, `cockpit grade --config cockpit.toml --criteria <file>` (a file inside the repository, relative or absolute) runs the
|
|
194
|
+
checks and the independent evaluator against the uncommitted change, and records nothing. The file has
|
|
195
|
+
the same front-matter `criteria` list, and optionally `scope`, `gates` and `objective`. Changes outside
|
|
196
|
+
that `scope` and flagged test changes become the standing criteria `scope-changes-necessary` and
|
|
197
|
+
`test-changes-justified`, judged by the evaluator.
|
|
198
|
+
|
|
199
|
+
## Test protection
|
|
200
|
+
|
|
201
|
+
An agent can make a check pass by weakening the tests behind it. Every `work grade`, in any
|
|
202
|
+
`[work] grading` mode, and `cockpit grade` therefore compare each checkout's tests with the base
|
|
203
|
+
commits the order recorded at acceptance (committed, staged, unstaged and new files; `cockpit grade`,
|
|
204
|
+
which has no order, compares with `HEAD`). Over the files cockpit treats as tests it flags:
|
|
205
|
+
|
|
206
|
+
- a test file deleted or moved out of the tests (`test-file-removed`);
|
|
207
|
+
- a test skipped, focused, marked todo or expected to fail: `it.skip`, `describe.only`, `test.todo`,
|
|
208
|
+
`xit`, `pytest.mark.skip`, `@unittest.skip` and the like (`test-skipped`);
|
|
209
|
+
- `@ts-ignore`, `@ts-nocheck` or a lint disable added to a test (`check-suppressed`);
|
|
210
|
+
- more tests or assertions removed than added, specific assertions replaced by weaker ones, or an
|
|
211
|
+
assertion that cannot fail added (`tests-removed`, `assertions-removed`, `assertions-loosened`,
|
|
212
|
+
`assertion-vacuous`);
|
|
213
|
+
- a runner's configuration or `package.json` test script that now excludes, ignores or tolerates the
|
|
214
|
+
absence of tests (`test-selection-narrowed`).
|
|
215
|
+
|
|
216
|
+
A diff cannot prove that a replacement keeps its force, so a removal is flagged as a candidate and
|
|
217
|
+
something that reads the change decides. The detection is textual, for JavaScript and TypeScript first
|
|
218
|
+
and the common Python forms; it is not a parser.
|
|
219
|
+
|
|
220
|
+
Which files are tests comes from `[testing] test_files`, globs relative to each checkout, when
|
|
221
|
+
declared. Otherwise cockpit uses its built-in patterns for common layouts (`*.test.*`, `*.spec.*`,
|
|
222
|
+
`__tests__/`, `tests/`, `test/`, `e2e/`, `test_*.py`, `*_test.py`, `conftest.py`, and a few others). The
|
|
223
|
+
grade result names which applied in `result.testProtection.testFiles`. Runner configuration
|
|
224
|
+
(`vitest.config.*`, `jest.config.*`, `playwright.config.*`, `pytest.ini`, `package.json` and similar) is
|
|
225
|
+
always watched.
|
|
226
|
+
|
|
227
|
+
How a finding is decided depends on [`[work] grading`](#how-an-order-earns-done):
|
|
228
|
+
|
|
229
|
+
- `independent`: the findings become the standing criterion `test-changes-justified`, which the
|
|
230
|
+
evaluator judges against the diff, with any acknowledgement notes recorded on the order as context.
|
|
231
|
+
`cockpit grade` does the same.
|
|
232
|
+
- `self`: the agent's verdict covers it, and its `--note` must name each flagged file.
|
|
233
|
+
- `checks`: no model reads the change, so a finding fails the grade as the criterion `test-protection`
|
|
234
|
+
until it is acknowledged.
|
|
235
|
+
|
|
236
|
+
An unmet verdict on either criterion reports `WORK_TEST_WEAKENED` with a fix. `test-run` runs the same
|
|
237
|
+
comparison against the base of each open order and reports the findings under `testProtection`; under
|
|
238
|
+
`checks` grading an unacknowledged finding fails the run with `WORK_TEST_WEAKENED` even when the gate
|
|
239
|
+
passed, and otherwise the grade judges it. With no open order it says in `testProtection` that it had
|
|
240
|
+
nothing to compare with.
|
|
241
|
+
|
|
242
|
+
`work acknowledge --work-order <id> --note <why it is not a weakening>` records an acknowledgement with
|
|
243
|
+
who passed it. It covers exactly the findings it showed, so a test deleted or skipped later fails a
|
|
244
|
+
`checks` grade again. `[work.gates] acknowledge` defaults to `agent`; a cockpit that sets it to `person`
|
|
245
|
+
has a person run it with `--interactive`, read the findings and type the digest, and an agent's run
|
|
246
|
+
without a terminal is refused with `WORK_PERSON_REQUIRED`.
|
|
247
|
+
|
|
248
|
+
## Decisions
|
|
249
|
+
|
|
250
|
+
<!-- cockpit:ref schema=docs.decisions --> <!-- cockpit:ref command=work decide --> A work order can record the lasting decisions it makes, and cockpit holds the order open until
|
|
251
|
+
each one is written down. This needs a directory of decision records in `cockpit.toml`; without it,
|
|
252
|
+
both commands refuse and name the setting:
|
|
253
|
+
|
|
254
|
+
```toml
|
|
255
|
+
[docs]
|
|
256
|
+
decisions = "docs/adr" # or "<sibling slug>:docs/adr" in a sibling
|
|
257
|
+
decisions_index = "docs/adr/README.md" # optional; new records are appended to it
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
```sh
|
|
261
|
+
npx --no cockpit work note --config cockpit.toml --work-order WO-1 --decision --text "Cache by tenant"
|
|
262
|
+
npx --no cockpit work decide --config cockpit.toml --work-order WO-1 --decision 3 --record
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
`work note --decision` records the decision on the order; `work status` lists it under
|
|
266
|
+
`openDecisions` until `work decide` resolves it in one of three ways:
|
|
267
|
+
|
|
268
|
+
- `--record` writes a new record, `NNNN-<slug>.md` with the next free number (a directory whose
|
|
269
|
+
records are named by date gets `YYYY-MM-DD-<slug>.md` instead). It holds the title,
|
|
270
|
+
`Status: accepted`, a `Work order: <id>` line and body sections whose placeholders the agent replaces.
|
|
271
|
+
It is appended to `decisions_index` when one is declared. `--supersedes <number>` adds a
|
|
272
|
+
`Supersedes:` line and sets that older record's status to `superseded by NNNN`.
|
|
273
|
+
- `--record-file <path>` cites an existing record under `decisions` that has a `Work order: <id>` line
|
|
274
|
+
(or a `work_order:` front-matter field), such as one the agent wrote itself. `--record` takes no
|
|
275
|
+
path: it always writes a new record. `--supersedes` applies only with `--record`; a cited record
|
|
276
|
+
carries its own `Supersedes:` line, and the older record's status is the agent's to change.
|
|
277
|
+
- `--none --reason <why>` says the decision is not a lasting one.
|
|
278
|
+
|
|
279
|
+
`work signoff` refuses any closure, partial and abandoned too, while a decision is unresolved or its
|
|
280
|
+
record is missing, no longer cites the order, or still holds the template's placeholders. A `--none`
|
|
281
|
+
resolution and its reason are shown in the signoff prompt, so the signoff gate covers them. The
|
|
282
|
+
`decisions` directory and `decisions_index` never count as outside an order's `scope`, whatever the
|
|
283
|
+
order lists and under every grading mode, because writing records there is part of every order's
|
|
284
|
+
work. A criteria file passed to `cockpit grade --criteria` has no such allowance. `work verify` checks each cited
|
|
285
|
+
record still exists and names its order; it does not compare record bodies, because superseding a
|
|
286
|
+
decision legitimately edits an older record.
|
|
287
|
+
|
|
288
|
+
`work accept` and `work status` list, under `relatedDecisions`, the records whose text names a path
|
|
289
|
+
inside the order's `scope`, so earlier decisions about that code are in front of the agent.
|
|
290
|
+
|
|
291
|
+
When `[docs]` is declared, every grade under `independent` or `self` grading carries standing
|
|
292
|
+
criteria. A model judges them: the evaluator in `independent` mode, the agent's own verdict in `self`.
|
|
293
|
+
|
|
294
|
+
- `decisions-recorded`, when `decisions` is set: every lasting decision in the change is recorded on
|
|
295
|
+
the order or in a decision record.
|
|
296
|
+
- `docs-updated`: documentation that describes behaviour the change alters is updated, or none
|
|
297
|
+
describes it.
|
|
298
|
+
|
|
299
|
+
Under `checks` grading no model reads the change, so both are instructions in the work skill and are
|
|
300
|
+
not enforced. Recording a decision at all is also instructed: an agent that never runs
|
|
301
|
+
`work note --decision` is caught only by the `decisions-recorded` criterion, and only where a model
|
|
302
|
+
grades.
|
|
303
|
+
|
|
304
|
+
## The independent evaluator
|
|
305
|
+
|
|
306
|
+
<!-- cockpit:ref schema=work.evaluators --> <!-- cockpit:ref schema=work.evaluator_timeout_seconds --> The grader runs headless in an agent tool from `work.evaluators`, whichever agent tool did the work,
|
|
307
|
+
so `independent` grading needs one of them on `PATH` and signed in. The list is tried in order (by
|
|
308
|
+
default the tools `surfaces.tools` lists that can evaluate, in that order, so a Claude Code-only cockpit
|
|
309
|
+
grades with Claude Code; when the command runs inside Claude Code or Codex, detected from `CLAUDECODE` or `CODEX_THREAD_ID` as measured 2026-11-03, that tool moves last so another listed tool grades first, and a list you write is used exactly as written; `--evaluator <tool>` on `work grade` or `grade --criteria` runs only that one tool for that run, with no fallback): a tool that is missing, too old for the flags below, signed out,
|
|
310
|
+
rate-limited or timed out is passed over and the next is tried, and the grade record names which tool
|
|
311
|
+
answered and which were passed over. When the tool that answered is the one running the command, the
|
|
312
|
+
command also prints a warning naming each tool passed over and why, because that is the weaker grade. An answer that fails cockpit's checks is refused rather than
|
|
313
|
+
retried with another tool, and nothing falls back to the agent grading its own work. Each grade is a
|
|
314
|
+
new run of its own, with no session saved to resume, so it never sees the session of the agent that did
|
|
315
|
+
the work; an answer from a session that already answered is refused:
|
|
316
|
+
|
|
317
|
+
| Tool | Runs | Read-only by | Install and sign in |
|
|
318
|
+
|---|---|---|---|
|
|
319
|
+
| `codexcli` | `codex exec --ephemeral --ignore-user-config` | `--sandbox read-only` | `npm install -g @openai/codex`, then `codex login` |
|
|
320
|
+
| `claudecode` | `claude --print --no-session-persistence --safe-mode --strict-mcp-config` | `--tools Read,Grep,Glob`, so no tool that writes or runs commands exists; `--permission-mode dontAsk` | `npm install -g @anthropic-ai/claude-code`, then `claude auth login` |
|
|
321
|
+
| `opencode` | `opencode run --pure` | `OPENCODE_PERMISSION` denying its edit, shell, task, web, skill, question, to-do and LSP tools, so they are not offered | `npm install -g opencode-ai`, then `opencode auth login` |
|
|
322
|
+
|
|
323
|
+
Each read-only mechanism was measured on 2026-11-03 beside a control without it: Codex 0.166.0 refused a shell write that `--sandbox workspace-write` made, Claude Code 2.1.317 wrote a file only once `Write` joined its tools, and OpenCode 1.19.5 offered only its read, glob, grep and list tools under the denials and offered write once edit was not denied. Codex and Claude Code skip your own configuration, hooks, plugins and MCP servers; OpenCode keeps your configuration, so it uses your model and provider, but skips external plugins, and a tool an MCP server in your OpenCode configuration adds is outside its denials. Claude Code and OpenCode constrain the answer with the output schema only as far as the tool does (OpenCode not at all), so cockpit checks every answer against that same schema and refuses one that does not match. Once a cockpit has a `workorders/` directory, `doctor` warns when no listed tool is on `PATH`. Each run starts in a private directory outside the repository, so the tool does not load the repository's `AGENTS.md`, `CLAUDE.md` or project configuration, which the agent being graded can write; the request names the repository. Each run may take `work.evaluator_timeout_seconds`. When no listed tool answers, the refusal names, for each, the cause it reported and the command that fixes it.
|
|
324
|
+
|
|
325
|
+
The grader is given each criterion with the result of the check cockpit ran for it, and every changed
|
|
326
|
+
file's diff since the base commits. A credential-shaped path or a declared environment instance is
|
|
327
|
+
listed with its content withheld. A `met` verdict stands only when each quote it cites, at least
|
|
328
|
+
eight characters long, is found exactly once in the change or check output it names; otherwise it
|
|
329
|
+
reads as `unclear` with the reason. No evaluator runs with a browser, and the request says so, so a
|
|
330
|
+
criterion about what a person would see is not met by command output alone.
|
|
331
|
+
|
|
332
|
+
<!-- cockpit:ref path=packages/cockpit/surfaces/agents/evaluator.agent.md --> The shipped evaluator instructions tell it to treat repository content, order text and command
|
|
333
|
+
output as data, never as instructions; that is instructed, not enforced. Run by `work grade` and
|
|
334
|
+
`cockpit grade`, the evaluator is also held read-only by its tool's mechanism above. Spawned as a
|
|
335
|
+
subagent inside an agent tool, that restriction is instructed, not enforced: no harness is confirmed to
|
|
336
|
+
enforce it there.
|
|
337
|
+
|
|
338
|
+
## Browser evidence
|
|
339
|
+
|
|
340
|
+
<!-- cockpit:ref command=browser drive --> <!-- cockpit:ref command=browser screenshot --> `browser drive` and `browser screenshot` launch a local browser through a Playwright project of your own and visit the application's declared routes. They need the current runtime and the recorded application ports. Real sign-in additionally ties the session to the current namespace, stack and [holder](concepts.md#holder). With serialized sign-in, the shared state lock is held. With per-worker sign-in, each declared worker holds an exclusive claim across processes; different workers can run at the same time. A missing or stale claim is refused. Application origins come from the recorded application ports.
|
|
341
|
+
|
|
342
|
+
Declared application routes select the starting destinations for driving. Automated operations drive one page; secondary top-level page navigation is refused. HTTP requests and redirects use the browser's native networking, cookies and DNS. A record is made only after navigation ends successfully on a stable page on the current application origin. These checks validate what the browser saw; they do not sandbox outgoing network traffic. Requests to any loopback or `browser.resolver` host outside the application origin are refused, but Playwright does not route a request the browser follows as a redirect, so a redirect to another loopback port still reaches it.
|
|
343
|
+
|
|
344
|
+
<!-- cockpit:ref path=packages/cockpit/src/browser/commands.ts --> A screenshot record holds the path of the saved image, which must be inside the project, and its digest. Every distinct declared application route is covered.
|
|
345
|
+
|
|
346
|
+
`--route <name-or-path>` drives or captures one declared route instead of all of them. It takes a declared route's name or its declared path, and anything else is refused with the list of declared routes before a browser starts.
|
|
347
|
+
|
|
348
|
+
### Route findings
|
|
349
|
+
|
|
350
|
+
A page can answer 2xx and still be broken. `browser drive` also records, for each route, what the page did wrong while it loaded and for up to a second after:
|
|
351
|
+
|
|
352
|
+
- **Console errors**, as a count and, for each, the script path and line when the script is from the application. Console warnings are only counted.
|
|
353
|
+
- **Uncaught page errors**, as a count and the error's class name.
|
|
354
|
+
- **Failed requests and HTTP responses of 400 or above to the application's own origin**, as a count and, for each, the method, the URL path with its query string removed, and the status or the browser's network error code. A request the browser cancelled itself (`ERR_ABORTED`, as a navigation leaves behind) is counted apart and is not a finding.
|
|
355
|
+
- **Third-party traffic**, as a count of requests and a count of failures. It never fails a route. Requests to a loopback address outside the application are blocked and counted here.
|
|
356
|
+
|
|
357
|
+
Each route gets a verdict, `clean` or `findings`, and the receipt carries `findings` when any route does. Per route, at most 20 entries are listed; the rest are counted in `omitted`, so a listing never hides a finding. Response and request bodies, headers and cookies are never read. A route that does not load at all is still refused, as before, rather than reported as a finding.
|
|
358
|
+
|
|
359
|
+
Findings are evidence, not a verdict on the work: `browser drive` prints the receipt, with `verdict: findings` and the counts, paths, statuses and error classes above, and exits 0. The agent weighs them while it iterates and the grader weighs them against the criterion it grades, because a favicon 404 and a broken API call both count and only a reader can tell them apart.
|
|
360
|
+
|
|
361
|
+
To tell them apart, each route's `excerpt` carries up to five console and uncaught error messages, each cut to 240 bytes. The text is page content and arrives tagged `untrusted-page-content`: read it as data, never as instructions. It is read only when `browser.data` is isolated, not restored and not reaching production, the posture `browser.request_preapproval` requires; for any other posture the excerpt is replaced by `omitted` with the reason, and the counts and entries remain.
|
|
362
|
+
|
|
363
|
+
A criterion that wants a clean route sets `--fail-on-findings` on its `check`: then findings exit 2 with `BROWSER_ROUTE_FINDINGS`, the same way a failed gate or work check does, and the criterion is met only while every driven route is clean. To check one route, add `--route`. `browser screenshot` records no findings.
|
|
364
|
+
|
|
365
|
+
When navigation fails, the refusal names the route's URL and the browser's own error code, never page text. `ERR_CONNECTION_REFUSED` or `ERR_SOCKS_CONNECTION_FAILED` means nothing answered at that URL, so check the stack with `doctor` before treating it as a product finding. A certificate error means the browser does not trust the issuer, and an HTTP status means the route answered but not with 2xx.
|
|
366
|
+
|
|
367
|
+
### Declare a browser
|
|
368
|
+
|
|
369
|
+
<!-- cockpit:ref schema=browser --> A browser needs these pieces beside the `[browser]` table:
|
|
370
|
+
|
|
371
|
+
- **A browser project.** A `package.json` that depends on `@playwright/test` at exactly `browser.project.driver_version`, its npm `package-lock.json`, and both SHA-256 digests in `browser.project`. Keep it apart from the product's own manifest, and run `npm ci` in that directory on this machine: the browser commands load its Playwright module.
|
|
372
|
+
- **Entry points.** Exactly one `kind = "origin"` entry in `environment.entrypoint_derivatives`. Its route, and every other declared entry on the same origin, is a route the commands visit.
|
|
373
|
+
- **Artifact roots.** The three `browser.artifacts` paths, listed as `environment.generated_host_paths`. The screenshot command creates the `cli` root when it is missing.
|
|
374
|
+
- **A measured harness row.** The commands drive through a `browser.harnesses` row whose version cockpit has measured; the rendered skill reports other versions as unavailable.
|
|
375
|
+
|
|
376
|
+
cockpit does not run a browser service or a browser debugger. To let an agent drive a browser through its own Playwright MCP tools, run a browser service in your own Compose file and name its loopback address in `browser.endpoint`. cockpit then publishes the Playwright MCP declaration, which you approve by setting `playwright` under `[mcp.approved]` to the sha256 `sync` reports (its server must be declared in a JSON file with an `mcpServers` object, listed in a sibling's `derives.mcp_sources`), and the `cockpit-browser` skill. Without an endpoint, the Playwright MCP server and the skill are reported unavailable and not rendered; `browser drive` and `browser screenshot` are the working path. The published MCP points at the endpoint as declared, so it reaches the stack started on the base port and does not follow a leased port offset of a second parallel stack. The MCP transports are not measured in any tool; the [capability matrix](capability-matrix.md) says so.
|
|
377
|
+
|
|
378
|
+
## Choose the proving test tier
|
|
379
|
+
|
|
380
|
+
<!-- cockpit:ref command=test-run --> <!-- cockpit:ref schema=testing.gates --> Product stages and gates are declared in configuration. Use the narrowest proving gate for isolated behavior, and the complete declared gate for shared behavior. Documentation-only changes need no behavioral gate when behavior is unchanged. `init` proposes stages and gates from the test entry points it finds. With no `[testing]` declared, the generated guide tells agents to add a characterization test in the product's own runner and never to report work as passing, and `doctor` warns that nothing can be graded PASS.
|
|
381
|
+
|
|
382
|
+
### Choosing stage commands
|
|
383
|
+
|
|
384
|
+
<!-- cockpit:ref schema=testing.stages --> Let the product's build or test tool decide what a change affects; cockpit runs it and reports the verdict. Declare the tool's affected or changed-since run as a targeted gate and its complete run as a full gate. A stage command is an argv array run without a shell, from the directory holding `cockpit.toml`. Its environment is `PATH` plus `HOME`, `USER`, `LOGNAME`, `TMPDIR`, `LANG`, `LC_ALL`, `LC_CTYPE` and `TZ` when set; every other variable, including credentials, is withheld. A stage that outlives its `timeout_seconds` is stopped and the gate reports DEGRADED, naming the field to raise; the default and ceiling are in the [configuration reference](configuration-reference.md). Output past the capture limit is dropped from the front and the stage is still judged by its exit status.
|
|
385
|
+
|
|
386
|
+
<!-- cockpit:ref schema=testing.stages --> `test-run --select <kind>:<value>` narrows a gate, where kind is `spec`, `file`, `test` or `route`. A stage receives the selection through its own `select` table: for each kind it accepts, the arguments to append in its tool's spelling, with `{value}` replaced by the selected value. A stage that declares no arguments for the selected kind is not run and reports DEGRADED rather than running unselected:
|
|
387
|
+
|
|
388
|
+
```toml
|
|
389
|
+
stages = [
|
|
390
|
+
{ id = "unit", command = ["npx", "vitest", "run"], requires_stack = false, select = { file = ["{value}"], test = ["-t", "{value}"] } },
|
|
391
|
+
]
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
The same shape fits other runners: Jest takes `file = ["{value}"]` and `test = ["-t", "{value}"]`, pytest takes `file = ["{value}"]` and `test = ["-k", "{value}"]`, and `go test ./...` takes `test = ["-run", "{value}"]`.
|
|
395
|
+
|
|
396
|
+
This Nx example assumes the product checkout is at `../web` and its mainline is `origin/main`:
|
|
397
|
+
|
|
398
|
+
```toml
|
|
399
|
+
[testing]
|
|
400
|
+
stages = [
|
|
401
|
+
{ id = "affected", command = ["sh", "-c", "cd ../web && exec npx nx affected -t test --base=origin/main"], requires_stack = false },
|
|
402
|
+
{ id = "all", command = ["sh", "-c", "cd ../web && exec npx nx run-many -t test"], requires_stack = false },
|
|
403
|
+
]
|
|
404
|
+
gates = [
|
|
405
|
+
{ id = "affected", tier = "targeted", stages = ["affected"], changes = "Isolated behavior; Nx selects the affected projects" },
|
|
406
|
+
{ id = "all", tier = "full", stages = ["all"], changes = "Shared or cross-project behavior" },
|
|
407
|
+
]
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
Nx compares the base with the current working tree, so uncommitted edits count. For other tools, keep the stage shape and change the command:
|
|
411
|
+
|
|
412
|
+
- **Bazel:** `bazel test //...` for both gates. With the default `--cache_test_results=auto`, Bazel reports cached results for tests whose inputs did not change and passed before, so the full run is already change-aware.
|
|
413
|
+
- **Turborepo:** `npx turbo run test --affected` for the targeted stage and `npx turbo run test` for the full one. Turborepo documents `--affected` as `--filter=...[main...HEAD]`, a comparison of commits, so commit work in progress before relying on it.
|
|
414
|
+
- **A runner's changed-file mode:** `npx vitest run --changed origin/main` or `npx jest --changedSince=origin/main` for the targeted stage, and the plain run for the full one.
|
|
415
|
+
|
|
416
|
+
<!-- cockpit:ref path=packages/cockpit/src/testing/verdict.ts --> Only a complete, stable declared gate whose checks all pass can report PASS. If a check ran and failed, the result is FAIL. If results are unavailable or malformed, it is DEGRADED. Otherwise, if the listed files changed or are stale, it is VOID. Otherwise, a subset or staged run is PARTIAL. A target selector passes your selection to the product's own tool and never substitutes a made-up pass. Every verdict returns the same result, with each stage's observation; any verdict but PASS also exits non-zero with `TEST_GATE_UNSATISFIED`.
|
|
417
|
+
|
|
418
|
+
<!-- cockpit:ref schema=testing.native_hooks.install --> Native hooks are inspect-only by default. Writing native hook output needs a policy tied to cockpit's ownership record and a measurement of its cost. Rendering a hook and describing how to activate it does not switch on the Git hook path. A person must install it and check separately that it works. Leave `native_hooks` out to keep that default; declare `native_hooks = { install = "explicit-native" }` only together with `native_hook_policy`.
|
|
419
|
+
|
|
420
|
+
See the generated [CLI reference](cli-reference.md), [configuration reference](configuration-reference.md), [capability matrix](capability-matrix.md) and [diagnostic index](troubleshooting.md) for the current declared surfaces and how far each is confirmed.
|