@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.
Files changed (426) hide show
  1. package/CHANGELOG.md +474 -0
  2. package/LICENSE +21 -0
  3. package/README.md +25 -2
  4. package/bin/cockpit.mjs +33 -0
  5. package/cockpit.schema.json +2644 -0
  6. package/dist/autonomy.d.ts +45 -0
  7. package/dist/autonomy.js +173 -0
  8. package/dist/bounded-read.d.ts +14 -0
  9. package/dist/bounded-read.js +42 -0
  10. package/dist/browser/commands.d.ts +117 -0
  11. package/dist/browser/commands.js +453 -0
  12. package/dist/browser/package-paths.d.ts +1 -0
  13. package/dist/browser/package-paths.js +6 -0
  14. package/dist/browser/proxy.d.ts +22 -0
  15. package/dist/browser/proxy.js +37 -0
  16. package/dist/browser/runtime.d.ts +118 -0
  17. package/dist/browser/runtime.js +186 -0
  18. package/dist/browser/surfaces.d.ts +141 -0
  19. package/dist/browser/surfaces.js +561 -0
  20. package/dist/browser/ui-gate.d.ts +15 -0
  21. package/dist/browser/ui-gate.js +18 -0
  22. package/dist/canonical-json.d.ts +2 -0
  23. package/dist/canonical-json.js +5 -0
  24. package/dist/cli-guard.d.ts +5 -0
  25. package/dist/cli-guard.js +71 -0
  26. package/dist/cli-main.d.ts +176 -0
  27. package/dist/cli-main.js +1584 -0
  28. package/dist/cli.d.ts +3 -0
  29. package/dist/cli.js +16 -0
  30. package/dist/command-table.d.ts +121 -0
  31. package/dist/command-table.js +664 -0
  32. package/dist/config/load.d.ts +183 -0
  33. package/dist/config/load.js +367 -0
  34. package/dist/config/sibling-toml.d.ts +48 -0
  35. package/dist/config/sibling-toml.js +160 -0
  36. package/dist/config/surface-tools-toml.d.ts +9 -0
  37. package/dist/config/surface-tools-toml.js +37 -0
  38. package/dist/config/unconfirmed-toml.d.ts +9 -0
  39. package/dist/config/unconfirmed-toml.js +29 -0
  40. package/dist/config/verified-write.d.ts +43 -0
  41. package/dist/config/verified-write.js +89 -0
  42. package/dist/diagnostics.d.ts +26 -0
  43. package/dist/diagnostics.js +344 -0
  44. package/dist/docs/check.d.ts +16 -0
  45. package/dist/docs/check.js +197 -0
  46. package/dist/docs/decision-record.d.ts +34 -0
  47. package/dist/docs/decision-record.js +135 -0
  48. package/dist/docs/decisions.d.ts +16 -0
  49. package/dist/docs/decisions.js +103 -0
  50. package/dist/docs/markdown.d.ts +36 -0
  51. package/dist/docs/markdown.js +88 -0
  52. package/dist/docs/references.d.ts +32 -0
  53. package/dist/docs/references.js +148 -0
  54. package/dist/emit.d.ts +22 -0
  55. package/dist/emit.js +43 -0
  56. package/dist/entrypoint-kinds.d.ts +3 -0
  57. package/dist/entrypoint-kinds.js +11 -0
  58. package/dist/environment/application/confirm.d.ts +35 -0
  59. package/dist/environment/application/confirm.js +122 -0
  60. package/dist/environment/application/destructive.d.ts +6 -0
  61. package/dist/environment/application/destructive.js +429 -0
  62. package/dist/environment/application/doctor.d.ts +94 -0
  63. package/dist/environment/application/doctor.js +247 -0
  64. package/dist/environment/application/guard.d.ts +49 -0
  65. package/dist/environment/application/guard.js +677 -0
  66. package/dist/environment/application/health.d.ts +143 -0
  67. package/dist/environment/application/health.js +385 -0
  68. package/dist/environment/application/lifecycle-context.d.ts +235 -0
  69. package/dist/environment/application/lifecycle-context.js +154 -0
  70. package/dist/environment/application/lifecycle-state.d.ts +25 -0
  71. package/dist/environment/application/lifecycle-state.js +202 -0
  72. package/dist/environment/application/lifecycle.d.ts +18 -0
  73. package/dist/environment/application/lifecycle.js +737 -0
  74. package/dist/environment/application/logs.d.ts +45 -0
  75. package/dist/environment/application/logs.js +127 -0
  76. package/dist/environment/application/services.d.ts +60 -0
  77. package/dist/environment/application/services.js +89 -0
  78. package/dist/environment/application/setup.d.ts +129 -0
  79. package/dist/environment/application/setup.js +741 -0
  80. package/dist/environment/application/shared.d.ts +11 -0
  81. package/dist/environment/application/shared.js +61 -0
  82. package/dist/environment/application/siblings.d.ts +43 -0
  83. package/dist/environment/application/siblings.js +269 -0
  84. package/dist/environment/claims.d.ts +389 -0
  85. package/dist/environment/claims.js +1701 -0
  86. package/dist/environment/codex-hook-trust.d.ts +11 -0
  87. package/dist/environment/codex-hook-trust.js +185 -0
  88. package/dist/environment/compose-environment.d.ts +1 -0
  89. package/dist/environment/compose-environment.js +6 -0
  90. package/dist/environment/compose-ownership.d.ts +21 -0
  91. package/dist/environment/compose-ownership.js +117 -0
  92. package/dist/environment/compose-topology.d.ts +125 -0
  93. package/dist/environment/compose-topology.js +490 -0
  94. package/dist/environment/contract.d.ts +522 -0
  95. package/dist/environment/contract.js +794 -0
  96. package/dist/environment/declaration.d.ts +14 -0
  97. package/dist/environment/declaration.js +39 -0
  98. package/dist/environment/destructive-composition.d.ts +29 -0
  99. package/dist/environment/destructive-composition.js +333 -0
  100. package/dist/environment/docker-daemon.d.ts +30 -0
  101. package/dist/environment/docker-daemon.js +78 -0
  102. package/dist/environment/docker-endpoint.d.ts +10 -0
  103. package/dist/environment/docker-endpoint.js +19 -0
  104. package/dist/environment/env-schema-observation.d.ts +46 -0
  105. package/dist/environment/env-schema-observation.js +241 -0
  106. package/dist/environment/evidence.d.ts +136 -0
  107. package/dist/environment/evidence.js +437 -0
  108. package/dist/environment/executable.d.ts +38 -0
  109. package/dist/environment/executable.js +190 -0
  110. package/dist/environment/generated-application/authorities.d.ts +5 -0
  111. package/dist/environment/generated-application/authorities.js +61 -0
  112. package/dist/environment/generated-application/bootstrap-skill.d.ts +16 -0
  113. package/dist/environment/generated-application/bootstrap-skill.js +328 -0
  114. package/dist/environment/generated-application/check.d.ts +13 -0
  115. package/dist/environment/generated-application/check.js +191 -0
  116. package/dist/environment/generated-application/custom-surface.d.ts +26 -0
  117. package/dist/environment/generated-application/custom-surface.js +289 -0
  118. package/dist/environment/generated-application/prepare.d.ts +29 -0
  119. package/dist/environment/generated-application/prepare.js +278 -0
  120. package/dist/environment/generated-application/publication.d.ts +33 -0
  121. package/dist/environment/generated-application/publication.js +547 -0
  122. package/dist/environment/generated-application/shared.d.ts +492 -0
  123. package/dist/environment/generated-application/shared.js +354 -0
  124. package/dist/environment/generated-application/surface-observation.d.ts +4 -0
  125. package/dist/environment/generated-application/surface-observation.js +69 -0
  126. package/dist/environment/generated-application/surface-outputs.d.ts +71 -0
  127. package/dist/environment/generated-application/surface-outputs.js +400 -0
  128. package/dist/environment/generated-application/surfaces.d.ts +3 -0
  129. package/dist/environment/generated-application/surfaces.js +704 -0
  130. package/dist/environment/generated-application/sync.d.ts +6 -0
  131. package/dist/environment/generated-application/sync.js +124 -0
  132. package/dist/environment/git-observation.d.ts +202 -0
  133. package/dist/environment/git-observation.js +553 -0
  134. package/dist/environment/health-composition.d.ts +12 -0
  135. package/dist/environment/health-composition.js +645 -0
  136. package/dist/environment/host-observation.d.ts +56 -0
  137. package/dist/environment/host-observation.js +52 -0
  138. package/dist/environment/identity.d.ts +48 -0
  139. package/dist/environment/identity.js +85 -0
  140. package/dist/environment/init-application.d.ts +333 -0
  141. package/dist/environment/init-application.js +726 -0
  142. package/dist/environment/install-policy-observation.d.ts +71 -0
  143. package/dist/environment/install-policy-observation.js +284 -0
  144. package/dist/environment/install-policy.d.ts +48 -0
  145. package/dist/environment/install-policy.js +96 -0
  146. package/dist/environment/instance.d.ts +33 -0
  147. package/dist/environment/instance.js +122 -0
  148. package/dist/environment/instruction-pointer.d.ts +19 -0
  149. package/dist/environment/instruction-pointer.js +144 -0
  150. package/dist/environment/lifecycle-composition.d.ts +31 -0
  151. package/dist/environment/lifecycle-composition.js +742 -0
  152. package/dist/environment/lifecycle-stage.d.ts +120 -0
  153. package/dist/environment/lifecycle-stage.js +408 -0
  154. package/dist/environment/lifecycle.d.ts +75 -0
  155. package/dist/environment/lifecycle.js +354 -0
  156. package/dist/environment/logs.d.ts +132 -0
  157. package/dist/environment/logs.js +519 -0
  158. package/dist/environment/map-limit.d.ts +2 -0
  159. package/dist/environment/map-limit.js +13 -0
  160. package/dist/environment/mcp-observation.d.ts +9 -0
  161. package/dist/environment/mcp-observation.js +46 -0
  162. package/dist/environment/observations.d.ts +46 -0
  163. package/dist/environment/observations.js +346 -0
  164. package/dist/environment/operator-application.d.ts +79 -0
  165. package/dist/environment/operator-application.js +197 -0
  166. package/dist/environment/ports.d.ts +182 -0
  167. package/dist/environment/ports.js +1205 -0
  168. package/dist/environment/posture-observation.d.ts +68 -0
  169. package/dist/environment/posture-observation.js +253 -0
  170. package/dist/environment/presence.d.ts +4 -0
  171. package/dist/environment/presence.js +26 -0
  172. package/dist/environment/read-composition.d.ts +32 -0
  173. package/dist/environment/read-composition.js +397 -0
  174. package/dist/environment/readiness-composition.d.ts +57 -0
  175. package/dist/environment/readiness-composition.js +151 -0
  176. package/dist/environment/reclaim.d.ts +370 -0
  177. package/dist/environment/reclaim.js +1940 -0
  178. package/dist/environment/repository-identity.d.ts +13 -0
  179. package/dist/environment/repository-identity.js +108 -0
  180. package/dist/environment/runtime-measurement-record.d.ts +38 -0
  181. package/dist/environment/runtime-measurement-record.js +111 -0
  182. package/dist/environment/runtime-measurement.d.ts +27 -0
  183. package/dist/environment/runtime-measurement.js +224 -0
  184. package/dist/environment/runtime-probe-residue.d.ts +43 -0
  185. package/dist/environment/runtime-probe-residue.js +148 -0
  186. package/dist/environment/runtime-probe.d.ts +72 -0
  187. package/dist/environment/runtime-probe.js +725 -0
  188. package/dist/environment/runtime.d.ts +551 -0
  189. package/dist/environment/runtime.js +2405 -0
  190. package/dist/environment/seed.d.ts +16 -0
  191. package/dist/environment/seed.js +43 -0
  192. package/dist/environment/selftest-application.d.ts +86 -0
  193. package/dist/environment/selftest-application.js +713 -0
  194. package/dist/environment/sensitive.d.ts +3 -0
  195. package/dist/environment/sensitive.js +48 -0
  196. package/dist/environment/served-checkout-grants.d.ts +53 -0
  197. package/dist/environment/served-checkout-grants.js +182 -0
  198. package/dist/environment/setup-observation.d.ts +62 -0
  199. package/dist/environment/setup-observation.js +1473 -0
  200. package/dist/environment/setup.d.ts +43 -0
  201. package/dist/environment/setup.js +176 -0
  202. package/dist/environment/sibling-checkouts.d.ts +119 -0
  203. package/dist/environment/sibling-checkouts.js +254 -0
  204. package/dist/environment/sibling-instructions.d.ts +33 -0
  205. package/dist/environment/sibling-instructions.js +224 -0
  206. package/dist/environment/sibling-observation.d.ts +27 -0
  207. package/dist/environment/sibling-observation.js +45 -0
  208. package/dist/environment/sibling-pull.d.ts +23 -0
  209. package/dist/environment/sibling-pull.js +95 -0
  210. package/dist/environment/sibling-registration.d.ts +45 -0
  211. package/dist/environment/sibling-registration.js +538 -0
  212. package/dist/environment/stack-inputs.d.ts +18 -0
  213. package/dist/environment/stack-inputs.js +210 -0
  214. package/dist/environment/stack-inventory-prune.d.ts +31 -0
  215. package/dist/environment/stack-inventory-prune.js +129 -0
  216. package/dist/environment/stack-inventory-report.d.ts +44 -0
  217. package/dist/environment/stack-inventory-report.js +78 -0
  218. package/dist/environment/stack-inventory.d.ts +94 -0
  219. package/dist/environment/stack-inventory.js +418 -0
  220. package/dist/environment/state.d.ts +410 -0
  221. package/dist/environment/state.js +2153 -0
  222. package/dist/environment/templates.d.ts +140 -0
  223. package/dist/environment/templates.js +685 -0
  224. package/dist/environment/tool-registration.d.ts +9 -0
  225. package/dist/environment/tool-registration.js +92 -0
  226. package/dist/environment/upgrade-application.d.ts +19 -0
  227. package/dist/environment/upgrade-application.js +175 -0
  228. package/dist/environment-exec/execute.d.ts +105 -0
  229. package/dist/environment-exec/execute.js +1179 -0
  230. package/dist/environment-exec/libexec-program.d.ts +6 -0
  231. package/dist/environment-exec/libexec-program.js +22 -0
  232. package/dist/environment-exec/verified-digest.d.ts +4 -0
  233. package/dist/environment-exec/verified-digest.js +16 -0
  234. package/dist/exact-keys.d.ts +7 -0
  235. package/dist/exact-keys.js +15 -0
  236. package/dist/fix-catalogue.d.ts +32 -0
  237. package/dist/fix-catalogue.js +60 -0
  238. package/dist/freshness.d.ts +29 -0
  239. package/dist/freshness.js +75 -0
  240. package/dist/generated-environment/adopt.d.ts +16 -0
  241. package/dist/generated-environment/adopt.js +271 -0
  242. package/dist/generated-environment/command.d.ts +47 -0
  243. package/dist/generated-environment/command.js +75 -0
  244. package/dist/generated-environment/transaction.d.ts +186 -0
  245. package/dist/generated-environment/transaction.js +1770 -0
  246. package/dist/grading/evaluate.d.ts +71 -0
  247. package/dist/grading/evaluate.js +403 -0
  248. package/dist/grading/grade.d.ts +33 -0
  249. package/dist/grading/grade.js +57 -0
  250. package/dist/guards/answer-confirmation.d.ts +41 -0
  251. package/dist/guards/answer-confirmation.js +109 -0
  252. package/dist/guards/evaluator.d.ts +130 -0
  253. package/dist/guards/evaluator.js +1258 -0
  254. package/dist/guards/harness-adapter.d.ts +17 -0
  255. package/dist/guards/harness-adapter.js +57 -0
  256. package/dist/guards/host.d.ts +8 -0
  257. package/dist/guards/host.js +10 -0
  258. package/dist/guards/invocation-parser.d.ts +66 -0
  259. package/dist/guards/invocation-parser.js +595 -0
  260. package/dist/guards/local-identity.d.ts +44 -0
  261. package/dist/guards/local-identity.js +129 -0
  262. package/dist/guards/policy-change.d.ts +43 -0
  263. package/dist/guards/policy-change.js +159 -0
  264. package/dist/guards/policy-pin.d.ts +13 -0
  265. package/dist/guards/policy-pin.js +177 -0
  266. package/dist/guards/protected-locations.d.ts +62 -0
  267. package/dist/guards/protected-locations.js +461 -0
  268. package/dist/guards/read-only.d.ts +37 -0
  269. package/dist/guards/read-only.js +315 -0
  270. package/dist/init/command.d.ts +41 -0
  271. package/dist/init/command.js +330 -0
  272. package/dist/init/derive.d.ts +53 -0
  273. package/dist/init/derive.js +819 -0
  274. package/dist/init/draft.d.ts +140 -0
  275. package/dist/init/draft.js +1228 -0
  276. package/dist/init/render.d.ts +47 -0
  277. package/dist/init/render.js +104 -0
  278. package/dist/init/scaffold.d.ts +53 -0
  279. package/dist/init/scaffold.js +121 -0
  280. package/dist/invocation.d.ts +13 -0
  281. package/dist/invocation.js +20 -0
  282. package/dist/package-metadata.d.ts +9 -0
  283. package/dist/package-metadata.js +19 -0
  284. package/dist/readiness.d.ts +53 -0
  285. package/dist/readiness.js +88 -0
  286. package/dist/references/named.d.ts +24 -0
  287. package/dist/references/named.js +27 -0
  288. package/dist/refusal.d.ts +15 -0
  289. package/dist/refusal.js +7 -0
  290. package/dist/registry-derivation.d.ts +31 -0
  291. package/dist/registry-derivation.js +32 -0
  292. package/dist/registry-resolve/command.d.ts +47 -0
  293. package/dist/registry-resolve/command.js +226 -0
  294. package/dist/registry-resolve/registry.d.ts +68 -0
  295. package/dist/registry-resolve/registry.js +292 -0
  296. package/dist/registry-resolve/render-shell.d.ts +18 -0
  297. package/dist/registry-resolve/render-shell.js +36 -0
  298. package/dist/repair.d.ts +29 -0
  299. package/dist/repair.js +8 -0
  300. package/dist/repository-path.d.ts +9 -0
  301. package/dist/repository-path.js +16 -0
  302. package/dist/schema-json.d.ts +1 -0
  303. package/dist/schema-json.js +177 -0
  304. package/dist/schema.d.ts +1289 -0
  305. package/dist/schema.js +985 -0
  306. package/dist/setup/command.d.ts +4 -0
  307. package/dist/setup/command.js +4 -0
  308. package/dist/sha256.d.ts +1 -0
  309. package/dist/sha256.js +4 -0
  310. package/dist/surfaces/adoption.d.ts +41 -0
  311. package/dist/surfaces/adoption.js +217 -0
  312. package/dist/surfaces/consumer-instructions.d.ts +20 -0
  313. package/dist/surfaces/consumer-instructions.js +43 -0
  314. package/dist/surfaces/contract.d.ts +42 -0
  315. package/dist/surfaces/contract.js +169 -0
  316. package/dist/surfaces/core-declarations.d.ts +24 -0
  317. package/dist/surfaces/core-declarations.js +79 -0
  318. package/dist/surfaces/development-markers.d.ts +1 -0
  319. package/dist/surfaces/development-markers.js +18 -0
  320. package/dist/surfaces/generator-adapter.d.ts +71 -0
  321. package/dist/surfaces/generator-adapter.js +809 -0
  322. package/dist/surfaces/harness-registry.d.ts +260 -0
  323. package/dist/surfaces/harness-registry.js +146 -0
  324. package/dist/surfaces/mcp.d.ts +145 -0
  325. package/dist/surfaces/mcp.js +349 -0
  326. package/dist/surfaces/merge.d.ts +30 -0
  327. package/dist/surfaces/merge.js +105 -0
  328. package/dist/surfaces/ownership.d.ts +190 -0
  329. package/dist/surfaces/ownership.js +795 -0
  330. package/dist/surfaces/projection.d.ts +136 -0
  331. package/dist/surfaces/projection.js +716 -0
  332. package/dist/surfaces/render.d.ts +79 -0
  333. package/dist/surfaces/render.js +636 -0
  334. package/dist/surfaces/restrictions.d.ts +130 -0
  335. package/dist/surfaces/restrictions.js +447 -0
  336. package/dist/surfaces/selftest.d.ts +162 -0
  337. package/dist/surfaces/selftest.js +393 -0
  338. package/dist/surfaces/skill-contract.d.ts +85 -0
  339. package/dist/surfaces/skill-contract.js +449 -0
  340. package/dist/surfaces/sync.d.ts +57 -0
  341. package/dist/surfaces/sync.js +164 -0
  342. package/dist/team-metadata.d.ts +41 -0
  343. package/dist/team-metadata.js +513 -0
  344. package/dist/testing/gates.d.ts +91 -0
  345. package/dist/testing/gates.js +182 -0
  346. package/dist/testing/hooks.d.ts +59 -0
  347. package/dist/testing/hooks.js +139 -0
  348. package/dist/testing/test-protection.d.ts +34 -0
  349. package/dist/testing/test-protection.js +137 -0
  350. package/dist/testing/verdict.d.ts +29 -0
  351. package/dist/testing/verdict.js +62 -0
  352. package/dist/testing/weakening.d.ts +15 -0
  353. package/dist/testing/weakening.js +30 -0
  354. package/dist/work-orders/application-closure.d.ts +7 -0
  355. package/dist/work-orders/application-closure.js +76 -0
  356. package/dist/work-orders/application-context.d.ts +162 -0
  357. package/dist/work-orders/application-context.js +137 -0
  358. package/dist/work-orders/application-decisions.d.ts +27 -0
  359. package/dist/work-orders/application-decisions.js +121 -0
  360. package/dist/work-orders/application-grading.d.ts +11 -0
  361. package/dist/work-orders/application-grading.js +212 -0
  362. package/dist/work-orders/application.d.ts +6 -0
  363. package/dist/work-orders/application.js +223 -0
  364. package/dist/work-orders/composition.d.ts +101 -0
  365. package/dist/work-orders/composition.js +1202 -0
  366. package/dist/work-orders/contract.d.ts +77 -0
  367. package/dist/work-orders/contract.js +140 -0
  368. package/dist/work-orders/decisions.d.ts +23 -0
  369. package/dist/work-orders/decisions.js +55 -0
  370. package/dist/work-orders/store.d.ts +207 -0
  371. package/dist/work-orders/store.js +291 -0
  372. package/docs/README.md +68 -0
  373. package/docs/architecture.md +136 -0
  374. package/docs/capability-matrix.md +58 -0
  375. package/docs/cli-reference.md +807 -0
  376. package/docs/command-list.md +62 -0
  377. package/docs/compose-patterns.md +99 -0
  378. package/docs/concepts.md +173 -0
  379. package/docs/configuration-essentials.md +177 -0
  380. package/docs/configuration-reference.md +636 -0
  381. package/docs/docs-check.md +76 -0
  382. package/docs/environment.md +948 -0
  383. package/docs/extending.md +43 -0
  384. package/docs/faq.md +113 -0
  385. package/docs/getting-started.md +692 -0
  386. package/docs/harness-surfaces.md +500 -0
  387. package/docs/joining-a-team.md +76 -0
  388. package/docs/release-policy.md +49 -0
  389. package/docs/safety-and-autonomy.md +463 -0
  390. package/docs/troubleshooting.md +382 -0
  391. package/docs/tutorial.md +171 -0
  392. package/docs/work-and-browser.md +420 -0
  393. package/libexec/browser-operation.cjs +270 -0
  394. package/libexec/fence-marker.cjs +101 -0
  395. package/libexec/fence-marker.d.cts +24 -0
  396. package/libexec/fenced-group-runner.cjs +77 -0
  397. package/libexec/fenced-supervisor.cjs +137 -0
  398. package/libexec/generated-filesystem.cjs +731 -0
  399. package/libexec/install-filesystem.cjs +225 -0
  400. package/libexec/rulesync-generator.NOTICE.md +1112 -0
  401. package/libexec/rulesync-generator.cjs +743 -0
  402. package/libexec/surface-generator-worker.cjs +266 -0
  403. package/libexec/surface-output-reader.cjs +99 -0
  404. package/libexec/surface-scratch-cleanup.cjs +14 -0
  405. package/libexec/validate-harness-evidence.d.mts +183 -0
  406. package/libexec/validate-harness-evidence.mjs +1312 -0
  407. package/package.json +74 -4
  408. package/surfaces/README.md +33 -0
  409. package/surfaces/agents/evaluator.agent.md +76 -0
  410. package/surfaces/guards/bash-guard.sh +48 -0
  411. package/surfaces/guards/claude.adapter.json +25 -0
  412. package/surfaces/guards/codex.adapter.json +24 -0
  413. package/surfaces/guards/opencode.adapter.json +25 -0
  414. package/surfaces/references/browser.md +63 -0
  415. package/surfaces/references/test-data-and-personas.md +84 -0
  416. package/surfaces/references/testing-tiers.md +11 -0
  417. package/surfaces/skills/cockpit-browser.skill.md +59 -0
  418. package/surfaces/skills/cockpit-explain.skill.md +32 -0
  419. package/surfaces/skills/cockpit-fix.skill.md +37 -0
  420. package/surfaces/skills/cockpit-setup.skill.md +39 -0
  421. package/surfaces/skills/cockpit-work.skill.md +34 -0
  422. package/surfaces/skills/collection.json +5 -0
  423. package/surfaces/skills/procedures/explain.md +66 -0
  424. package/surfaces/skills/procedures/fix.md +95 -0
  425. package/surfaces/skills/procedures/setup.md +452 -0
  426. 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.