@b00dea/cockpit 0.0.0-stage → 0.1.0

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 (363) hide show
  1. package/CHANGELOG.md +375 -0
  2. package/LICENSE +21 -0
  3. package/README.md +22 -2
  4. package/bin/cockpit.mjs +33 -0
  5. package/cockpit.schema.json +2574 -0
  6. package/dist/autonomy.d.ts +44 -0
  7. package/dist/autonomy.js +156 -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 +62 -0
  11. package/dist/browser/commands.js +349 -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 +117 -0
  17. package/dist/browser/runtime.js +183 -0
  18. package/dist/browser/surfaces.d.ts +141 -0
  19. package/dist/browser/surfaces.js +556 -0
  20. package/dist/browser/ui-gate.d.ts +15 -0
  21. package/dist/browser/ui-gate.js +18 -0
  22. package/dist/cli-guard.d.ts +5 -0
  23. package/dist/cli-guard.js +71 -0
  24. package/dist/cli-main.d.ts +139 -0
  25. package/dist/cli-main.js +1405 -0
  26. package/dist/cli.d.ts +3 -0
  27. package/dist/cli.js +16 -0
  28. package/dist/command-table.d.ts +113 -0
  29. package/dist/command-table.js +512 -0
  30. package/dist/config/load.d.ts +171 -0
  31. package/dist/config/load.js +345 -0
  32. package/dist/config/sibling-toml.d.ts +48 -0
  33. package/dist/config/sibling-toml.js +160 -0
  34. package/dist/config/surface-tools-toml.d.ts +9 -0
  35. package/dist/config/surface-tools-toml.js +37 -0
  36. package/dist/config/verified-write.d.ts +43 -0
  37. package/dist/config/verified-write.js +89 -0
  38. package/dist/diagnostics.d.ts +26 -0
  39. package/dist/diagnostics.js +335 -0
  40. package/dist/emit.d.ts +22 -0
  41. package/dist/emit.js +43 -0
  42. package/dist/entrypoint-kinds.d.ts +3 -0
  43. package/dist/entrypoint-kinds.js +11 -0
  44. package/dist/environment/application/destructive.d.ts +6 -0
  45. package/dist/environment/application/destructive.js +425 -0
  46. package/dist/environment/application/doctor.d.ts +89 -0
  47. package/dist/environment/application/doctor.js +235 -0
  48. package/dist/environment/application/guard.d.ts +43 -0
  49. package/dist/environment/application/guard.js +622 -0
  50. package/dist/environment/application/health.d.ts +134 -0
  51. package/dist/environment/application/health.js +379 -0
  52. package/dist/environment/application/lifecycle-context.d.ts +228 -0
  53. package/dist/environment/application/lifecycle-context.js +154 -0
  54. package/dist/environment/application/lifecycle-state.d.ts +25 -0
  55. package/dist/environment/application/lifecycle-state.js +201 -0
  56. package/dist/environment/application/lifecycle.d.ts +17 -0
  57. package/dist/environment/application/lifecycle.js +729 -0
  58. package/dist/environment/application/logs.d.ts +45 -0
  59. package/dist/environment/application/logs.js +127 -0
  60. package/dist/environment/application/setup.d.ts +129 -0
  61. package/dist/environment/application/setup.js +741 -0
  62. package/dist/environment/application/shared.d.ts +11 -0
  63. package/dist/environment/application/shared.js +61 -0
  64. package/dist/environment/claims.d.ts +389 -0
  65. package/dist/environment/claims.js +1709 -0
  66. package/dist/environment/codex-hook-trust.d.ts +11 -0
  67. package/dist/environment/codex-hook-trust.js +185 -0
  68. package/dist/environment/compose-environment.d.ts +1 -0
  69. package/dist/environment/compose-environment.js +6 -0
  70. package/dist/environment/compose-ownership.d.ts +21 -0
  71. package/dist/environment/compose-ownership.js +117 -0
  72. package/dist/environment/compose-topology.d.ts +117 -0
  73. package/dist/environment/compose-topology.js +413 -0
  74. package/dist/environment/contract.d.ts +489 -0
  75. package/dist/environment/contract.js +761 -0
  76. package/dist/environment/declaration.d.ts +14 -0
  77. package/dist/environment/declaration.js +39 -0
  78. package/dist/environment/destructive-composition.d.ts +29 -0
  79. package/dist/environment/destructive-composition.js +333 -0
  80. package/dist/environment/docker-daemon.d.ts +30 -0
  81. package/dist/environment/docker-daemon.js +78 -0
  82. package/dist/environment/docker-endpoint.d.ts +10 -0
  83. package/dist/environment/docker-endpoint.js +19 -0
  84. package/dist/environment/env-schema-observation.d.ts +46 -0
  85. package/dist/environment/env-schema-observation.js +241 -0
  86. package/dist/environment/evidence.d.ts +136 -0
  87. package/dist/environment/evidence.js +437 -0
  88. package/dist/environment/executable.d.ts +26 -0
  89. package/dist/environment/executable.js +167 -0
  90. package/dist/environment/generated-application/authorities.d.ts +5 -0
  91. package/dist/environment/generated-application/authorities.js +61 -0
  92. package/dist/environment/generated-application/bootstrap-skill.d.ts +16 -0
  93. package/dist/environment/generated-application/bootstrap-skill.js +328 -0
  94. package/dist/environment/generated-application/check.d.ts +13 -0
  95. package/dist/environment/generated-application/check.js +189 -0
  96. package/dist/environment/generated-application/custom-surface.d.ts +26 -0
  97. package/dist/environment/generated-application/custom-surface.js +289 -0
  98. package/dist/environment/generated-application/prepare.d.ts +29 -0
  99. package/dist/environment/generated-application/prepare.js +276 -0
  100. package/dist/environment/generated-application/publication.d.ts +33 -0
  101. package/dist/environment/generated-application/publication.js +547 -0
  102. package/dist/environment/generated-application/shared.d.ts +484 -0
  103. package/dist/environment/generated-application/shared.js +349 -0
  104. package/dist/environment/generated-application/surface-observation.d.ts +4 -0
  105. package/dist/environment/generated-application/surface-observation.js +69 -0
  106. package/dist/environment/generated-application/surface-outputs.d.ts +71 -0
  107. package/dist/environment/generated-application/surface-outputs.js +389 -0
  108. package/dist/environment/generated-application/surfaces.d.ts +3 -0
  109. package/dist/environment/generated-application/surfaces.js +699 -0
  110. package/dist/environment/generated-application/sync.d.ts +6 -0
  111. package/dist/environment/generated-application/sync.js +109 -0
  112. package/dist/environment/git-observation.d.ts +183 -0
  113. package/dist/environment/git-observation.js +544 -0
  114. package/dist/environment/health-composition.d.ts +11 -0
  115. package/dist/environment/health-composition.js +628 -0
  116. package/dist/environment/host-observation.d.ts +56 -0
  117. package/dist/environment/host-observation.js +52 -0
  118. package/dist/environment/identity.d.ts +48 -0
  119. package/dist/environment/identity.js +85 -0
  120. package/dist/environment/init-application.d.ts +308 -0
  121. package/dist/environment/init-application.js +697 -0
  122. package/dist/environment/install-policy-observation.d.ts +71 -0
  123. package/dist/environment/install-policy-observation.js +284 -0
  124. package/dist/environment/install-policy.d.ts +48 -0
  125. package/dist/environment/install-policy.js +96 -0
  126. package/dist/environment/instance.d.ts +33 -0
  127. package/dist/environment/instance.js +122 -0
  128. package/dist/environment/instruction-pointer.d.ts +19 -0
  129. package/dist/environment/instruction-pointer.js +144 -0
  130. package/dist/environment/lifecycle-composition.d.ts +29 -0
  131. package/dist/environment/lifecycle-composition.js +675 -0
  132. package/dist/environment/lifecycle-stage.d.ts +115 -0
  133. package/dist/environment/lifecycle-stage.js +398 -0
  134. package/dist/environment/lifecycle.d.ts +75 -0
  135. package/dist/environment/lifecycle.js +354 -0
  136. package/dist/environment/logs.d.ts +132 -0
  137. package/dist/environment/logs.js +519 -0
  138. package/dist/environment/observations.d.ts +46 -0
  139. package/dist/environment/observations.js +344 -0
  140. package/dist/environment/operator-application.d.ts +50 -0
  141. package/dist/environment/operator-application.js +155 -0
  142. package/dist/environment/ports.d.ts +182 -0
  143. package/dist/environment/ports.js +1205 -0
  144. package/dist/environment/posture-observation.d.ts +68 -0
  145. package/dist/environment/posture-observation.js +253 -0
  146. package/dist/environment/read-composition.d.ts +27 -0
  147. package/dist/environment/read-composition.js +352 -0
  148. package/dist/environment/readiness-composition.d.ts +38 -0
  149. package/dist/environment/readiness-composition.js +130 -0
  150. package/dist/environment/reclaim.d.ts +333 -0
  151. package/dist/environment/reclaim.js +1835 -0
  152. package/dist/environment/repository-identity.d.ts +13 -0
  153. package/dist/environment/repository-identity.js +108 -0
  154. package/dist/environment/runtime-measurement-record.d.ts +38 -0
  155. package/dist/environment/runtime-measurement-record.js +111 -0
  156. package/dist/environment/runtime-measurement.d.ts +27 -0
  157. package/dist/environment/runtime-measurement.js +224 -0
  158. package/dist/environment/runtime-probe-residue.d.ts +43 -0
  159. package/dist/environment/runtime-probe-residue.js +148 -0
  160. package/dist/environment/runtime-probe.d.ts +72 -0
  161. package/dist/environment/runtime-probe.js +725 -0
  162. package/dist/environment/runtime.d.ts +505 -0
  163. package/dist/environment/runtime.js +2335 -0
  164. package/dist/environment/seed.d.ts +16 -0
  165. package/dist/environment/seed.js +43 -0
  166. package/dist/environment/selftest-application.d.ts +86 -0
  167. package/dist/environment/selftest-application.js +713 -0
  168. package/dist/environment/sensitive.d.ts +3 -0
  169. package/dist/environment/sensitive.js +48 -0
  170. package/dist/environment/setup-observation.d.ts +62 -0
  171. package/dist/environment/setup-observation.js +1473 -0
  172. package/dist/environment/setup.d.ts +43 -0
  173. package/dist/environment/setup.js +176 -0
  174. package/dist/environment/sibling-instructions.d.ts +33 -0
  175. package/dist/environment/sibling-instructions.js +224 -0
  176. package/dist/environment/sibling-registration.d.ts +45 -0
  177. package/dist/environment/sibling-registration.js +538 -0
  178. package/dist/environment/state.d.ts +371 -0
  179. package/dist/environment/state.js +2013 -0
  180. package/dist/environment/templates.d.ts +140 -0
  181. package/dist/environment/templates.js +685 -0
  182. package/dist/environment/tool-registration.d.ts +9 -0
  183. package/dist/environment/tool-registration.js +96 -0
  184. package/dist/environment/upgrade-application.d.ts +19 -0
  185. package/dist/environment/upgrade-application.js +175 -0
  186. package/dist/environment-exec/execute.d.ts +102 -0
  187. package/dist/environment-exec/execute.js +1175 -0
  188. package/dist/environment-exec/libexec-program.d.ts +6 -0
  189. package/dist/environment-exec/libexec-program.js +22 -0
  190. package/dist/environment-exec/verified-digest.d.ts +4 -0
  191. package/dist/environment-exec/verified-digest.js +16 -0
  192. package/dist/exact-keys.d.ts +7 -0
  193. package/dist/exact-keys.js +15 -0
  194. package/dist/fix-catalogue.d.ts +32 -0
  195. package/dist/fix-catalogue.js +60 -0
  196. package/dist/freshness.d.ts +29 -0
  197. package/dist/freshness.js +75 -0
  198. package/dist/generated-environment/adopt.d.ts +16 -0
  199. package/dist/generated-environment/adopt.js +275 -0
  200. package/dist/generated-environment/command.d.ts +47 -0
  201. package/dist/generated-environment/command.js +75 -0
  202. package/dist/generated-environment/transaction.d.ts +186 -0
  203. package/dist/generated-environment/transaction.js +1770 -0
  204. package/dist/grading/evaluate.d.ts +71 -0
  205. package/dist/grading/evaluate.js +403 -0
  206. package/dist/grading/grade.d.ts +33 -0
  207. package/dist/grading/grade.js +57 -0
  208. package/dist/guards/evaluator.d.ts +113 -0
  209. package/dist/guards/evaluator.js +1226 -0
  210. package/dist/guards/harness-adapter.d.ts +17 -0
  211. package/dist/guards/harness-adapter.js +57 -0
  212. package/dist/guards/host.d.ts +8 -0
  213. package/dist/guards/host.js +10 -0
  214. package/dist/guards/invocation-parser.d.ts +66 -0
  215. package/dist/guards/invocation-parser.js +595 -0
  216. package/dist/guards/local-identity.d.ts +40 -0
  217. package/dist/guards/local-identity.js +123 -0
  218. package/dist/guards/policy-pin.d.ts +13 -0
  219. package/dist/guards/policy-pin.js +175 -0
  220. package/dist/guards/protected-locations.d.ts +62 -0
  221. package/dist/guards/protected-locations.js +461 -0
  222. package/dist/guards/read-only.d.ts +37 -0
  223. package/dist/guards/read-only.js +315 -0
  224. package/dist/init/command.d.ts +40 -0
  225. package/dist/init/command.js +310 -0
  226. package/dist/init/derive.d.ts +51 -0
  227. package/dist/init/derive.js +715 -0
  228. package/dist/init/draft.d.ts +138 -0
  229. package/dist/init/draft.js +1205 -0
  230. package/dist/init/render.d.ts +35 -0
  231. package/dist/init/render.js +82 -0
  232. package/dist/init/scaffold.d.ts +53 -0
  233. package/dist/init/scaffold.js +121 -0
  234. package/dist/invocation.d.ts +13 -0
  235. package/dist/invocation.js +20 -0
  236. package/dist/package-metadata.d.ts +9 -0
  237. package/dist/package-metadata.js +19 -0
  238. package/dist/readiness.d.ts +53 -0
  239. package/dist/readiness.js +88 -0
  240. package/dist/references/named.d.ts +24 -0
  241. package/dist/references/named.js +27 -0
  242. package/dist/refusal.d.ts +15 -0
  243. package/dist/refusal.js +7 -0
  244. package/dist/registry-derivation.d.ts +31 -0
  245. package/dist/registry-derivation.js +32 -0
  246. package/dist/registry-resolve/command.d.ts +47 -0
  247. package/dist/registry-resolve/command.js +226 -0
  248. package/dist/registry-resolve/registry.d.ts +68 -0
  249. package/dist/registry-resolve/registry.js +292 -0
  250. package/dist/registry-resolve/render-shell.d.ts +18 -0
  251. package/dist/registry-resolve/render-shell.js +36 -0
  252. package/dist/repair.d.ts +29 -0
  253. package/dist/repair.js +8 -0
  254. package/dist/schema-json.d.ts +1 -0
  255. package/dist/schema-json.js +177 -0
  256. package/dist/schema.d.ts +1322 -0
  257. package/dist/schema.js +934 -0
  258. package/dist/setup/command.d.ts +4 -0
  259. package/dist/setup/command.js +4 -0
  260. package/dist/sha256.d.ts +1 -0
  261. package/dist/sha256.js +4 -0
  262. package/dist/surfaces/adoption.d.ts +41 -0
  263. package/dist/surfaces/adoption.js +217 -0
  264. package/dist/surfaces/consumer-instructions.d.ts +20 -0
  265. package/dist/surfaces/consumer-instructions.js +43 -0
  266. package/dist/surfaces/contract.d.ts +42 -0
  267. package/dist/surfaces/contract.js +169 -0
  268. package/dist/surfaces/core-declarations.d.ts +24 -0
  269. package/dist/surfaces/core-declarations.js +79 -0
  270. package/dist/surfaces/development-markers.d.ts +1 -0
  271. package/dist/surfaces/development-markers.js +18 -0
  272. package/dist/surfaces/generator-adapter.d.ts +71 -0
  273. package/dist/surfaces/generator-adapter.js +809 -0
  274. package/dist/surfaces/harness-registry.d.ts +180 -0
  275. package/dist/surfaces/harness-registry.js +117 -0
  276. package/dist/surfaces/mcp.d.ts +95 -0
  277. package/dist/surfaces/mcp.js +186 -0
  278. package/dist/surfaces/merge.d.ts +30 -0
  279. package/dist/surfaces/merge.js +105 -0
  280. package/dist/surfaces/ownership.d.ts +190 -0
  281. package/dist/surfaces/ownership.js +795 -0
  282. package/dist/surfaces/projection.d.ts +136 -0
  283. package/dist/surfaces/projection.js +681 -0
  284. package/dist/surfaces/render.d.ts +118 -0
  285. package/dist/surfaces/render.js +633 -0
  286. package/dist/surfaces/restrictions.d.ts +130 -0
  287. package/dist/surfaces/restrictions.js +447 -0
  288. package/dist/surfaces/selftest.d.ts +162 -0
  289. package/dist/surfaces/selftest.js +393 -0
  290. package/dist/surfaces/skill-contract.d.ts +85 -0
  291. package/dist/surfaces/skill-contract.js +449 -0
  292. package/dist/surfaces/sync.d.ts +57 -0
  293. package/dist/surfaces/sync.js +164 -0
  294. package/dist/team-metadata.d.ts +41 -0
  295. package/dist/team-metadata.js +512 -0
  296. package/dist/testing/gates.d.ts +91 -0
  297. package/dist/testing/gates.js +182 -0
  298. package/dist/testing/hooks.d.ts +59 -0
  299. package/dist/testing/hooks.js +139 -0
  300. package/dist/testing/verdict.d.ts +29 -0
  301. package/dist/testing/verdict.js +62 -0
  302. package/dist/work-orders/application.d.ts +99 -0
  303. package/dist/work-orders/application.js +383 -0
  304. package/dist/work-orders/composition.d.ts +124 -0
  305. package/dist/work-orders/composition.js +1010 -0
  306. package/dist/work-orders/contract.d.ts +61 -0
  307. package/dist/work-orders/contract.js +122 -0
  308. package/dist/work-orders/store.d.ts +158 -0
  309. package/dist/work-orders/store.js +197 -0
  310. package/docs/README.md +65 -0
  311. package/docs/architecture.md +136 -0
  312. package/docs/capability-matrix.md +50 -0
  313. package/docs/cli-reference.md +599 -0
  314. package/docs/command-list.md +51 -0
  315. package/docs/compose-patterns.md +99 -0
  316. package/docs/concepts.md +171 -0
  317. package/docs/configuration-essentials.md +172 -0
  318. package/docs/configuration-reference.md +621 -0
  319. package/docs/environment.md +760 -0
  320. package/docs/extending.md +43 -0
  321. package/docs/faq.md +111 -0
  322. package/docs/getting-started.md +608 -0
  323. package/docs/harness-surfaces.md +433 -0
  324. package/docs/joining-a-team.md +76 -0
  325. package/docs/release-policy.md +49 -0
  326. package/docs/safety-and-autonomy.md +419 -0
  327. package/docs/troubleshooting.md +361 -0
  328. package/docs/tutorial.md +170 -0
  329. package/docs/work-and-browser.md +254 -0
  330. package/libexec/browser-operation.cjs +186 -0
  331. package/libexec/fence-marker.cjs +101 -0
  332. package/libexec/fence-marker.d.cts +24 -0
  333. package/libexec/fenced-group-runner.cjs +77 -0
  334. package/libexec/fenced-supervisor.cjs +137 -0
  335. package/libexec/generated-filesystem.cjs +731 -0
  336. package/libexec/install-filesystem.cjs +225 -0
  337. package/libexec/rulesync-generator.NOTICE.md +1112 -0
  338. package/libexec/rulesync-generator.cjs +743 -0
  339. package/libexec/surface-generator-worker.cjs +266 -0
  340. package/libexec/surface-output-reader.cjs +99 -0
  341. package/libexec/surface-scratch-cleanup.cjs +14 -0
  342. package/libexec/validate-harness-evidence.d.mts +183 -0
  343. package/libexec/validate-harness-evidence.mjs +1312 -0
  344. package/package.json +74 -4
  345. package/surfaces/README.md +33 -0
  346. package/surfaces/agents/evaluator.agent.md +76 -0
  347. package/surfaces/guards/bash-guard.sh +48 -0
  348. package/surfaces/guards/claude.adapter.json +25 -0
  349. package/surfaces/guards/codex.adapter.json +24 -0
  350. package/surfaces/guards/opencode.adapter.json +25 -0
  351. package/surfaces/references/browser.md +63 -0
  352. package/surfaces/references/test-data-and-personas.md +84 -0
  353. package/surfaces/references/testing-tiers.md +11 -0
  354. package/surfaces/skills/cockpit-browser.skill.md +54 -0
  355. package/surfaces/skills/cockpit-explain.skill.md +32 -0
  356. package/surfaces/skills/cockpit-fix.skill.md +37 -0
  357. package/surfaces/skills/cockpit-setup.skill.md +39 -0
  358. package/surfaces/skills/cockpit-work.skill.md +34 -0
  359. package/surfaces/skills/collection.json +5 -0
  360. package/surfaces/skills/procedures/explain.md +61 -0
  361. package/surfaces/skills/procedures/fix.md +81 -0
  362. package/surfaces/skills/procedures/setup.md +379 -0
  363. package/surfaces/skills/procedures/work.md +105 -0
@@ -0,0 +1,433 @@
1
+ # Harness surfaces
2
+
3
+ This page is for people reviewing the agent configuration `cockpit sync` generates, and for
4
+ integrators extending it. It covers what cockpit writes for each supported agent tool (Claude Code,
5
+ Codex CLI, OpenCode, Cursor and Grok Build), how product-specific additions enter, and how far
6
+ each generated feature is confirmed to work. Maintainers find the modules and tests behind it in
7
+ the contributor page `docs/contributing/testing.md`.
8
+
9
+ ## Publish and verify
10
+
11
+ [Surfaces](concepts.md#surface) are published by the same `sync` and checked by the same `check`
12
+ as the rest of the generated files; follow
13
+ [Bring the product up](getting-started.md#bring-the-product-up). `check` reports
14
+ [drift](concepts.md#drift) and never repairs output.
15
+
16
+ The repository action at `.github/actions/cockpit-check/action.yml` runs only `cockpit check`.
17
+ Install the exact cockpit version from your lockfile before calling it; the action does not
18
+ download cockpit.
19
+
20
+ ## Ownership and extension
21
+
22
+ Cockpit owns each generated entry either as a whole file or as a marked region inside a shared
23
+ file. The ownership manifest records the expected type, bytes and sources. Its digest catches
24
+ accidental changes; it does not prove who wrote a file in the past.
25
+
26
+ Removing a stale entry needs your separate approval of those exact paths and bytes: plain `sync`
27
+ refuses, and `sync --interactive` asks you to type the digest the dry run showed. A stale path whose
28
+ contents changed stays a conflict for you to resolve; [Check and sync](environment.md#check-and-sync)
29
+ has the full procedure.
30
+
31
+ A team's existing `.claude/settings.json`, `.codex/config.toml` or `.codex/hooks.json` is not
32
+ overwritten: [adopt it](getting-started.md#adopt-existing-agent-settings) and cockpit renders a merge of
33
+ the team's copy and its own output.
34
+
35
+ Common root instructions are written once, in the region of **AGENTS.md** that cockpit owns.
36
+ Claude's region contains only `@AGENTS.md`. When a team's existing **CLAUDE.md** already has that
37
+ exact import, cockpit leaves the file alone; removing the import makes `check` report drift.
38
+ Because which file imports which decides what every agent session loads, a person approves those
39
+ changes and runs `sync`.
40
+
41
+ Core declarations and `[surfaces].overlays` merge by name. An overlay that reuses a core name must
42
+ set `replaces` to that name and the recorded SHA-256 of the original. An overlay cannot replace
43
+ `permissions` or `mcp`. When a later cockpit version changes an original you overrode,
44
+ `OVERRIDDEN_CORE_CHANGED` names the overlay and the current digest, and `sync` and `check` refuse
45
+ until you review the new original and update `replaces.sha256`. `sync --dry-run` and `doctor` list
46
+ active overrides and changed originals from a read-only generation preview, and `doctor` says so
47
+ when the preview cannot run. Markdown frontmatter you write must use plain `---` YAML delimiters
48
+ (no language tag) and valid YAML of reasonable size; anything else is rejected before the generator
49
+ runs. A rules overlay is written into the instruction file every harness loads at start, so Rulesync
50
+ frontmatter such as `root: false` is accepted, but one that narrows itself with `globs` is refused
51
+ as `SURFACE_RULE_SCOPE_UNSUPPORTED`.
52
+ [Extending cockpit](extending.md) lists every extension point and the build-beside pattern.
53
+
54
+ The generator uses a checked-in, SHA-pinned bundle of Rulesync only to spell the output for each
55
+ harness. Packaging verifies the bundle against its source and includes its third-party notices,
56
+ and cockpit checks the bundle's bytes before loading it. Cockpit itself handles declaration
57
+ merging, restriction policy, MCP approval, sibling guide copies, capability state, the output file
58
+ list, ownership and publication. It accepts a generator result only when the files the generator
59
+ reports match the files read back from its isolated output directory.
60
+
61
+ Setting `[surfaces].bundles = ["claudecode-plugin"]` also publishes a Claude plugin bundle at
62
+ **.cockpit/bundles/claudecode-plugin/**: a manifest plus the generated skills (with the references
63
+ they tell the agent to read), subagents, overlay hooks and MCP declaration that apply. It does not
64
+ carry the guard hook, which reads the cockpit checkout and stays in the checkout's own
65
+ `.claude/settings.json`. These files share the ownership and drift check of other surfaces, and
66
+ a file in that directory that cockpit does not own is left alone. Writing the bundle does not show
67
+ that Claude loaded it; that needs a run in Claude Code.
68
+
69
+ ## Capability states
70
+
71
+ Each feature (rules, MCP servers, subagents, skills, hooks, permissions) has one of four states
72
+ per harness:
73
+
74
+ - `enforced`: the harness has a mechanism that can refuse the forbidden operation, and a dated
75
+ test with a deliberately broken control has confirmed it.
76
+ - `instructed`: cockpit writes guidance or a harness setting, but nothing makes the agent follow
77
+ it.
78
+ - `generated`: cockpit writes the file for a harness that has no guard adapter or loading test,
79
+ so nobody has verified that the tool even loads it.
80
+ - `unavailable`: cockpit writes nothing for this feature and records why the harness cannot
81
+ provide it.
82
+
83
+ Native spellings differ per harness, and generating a file never upgrades a state: a feature moves
84
+ to `enforced` only after a dated run of the real tool says so.
85
+
86
+ The shared guard is generated only for harnesses with a checked-in guard adapter: Claude Code,
87
+ Codex and OpenCode. The guard scripts deny, and fail closed, whenever a harness runs them. Whether a
88
+ harness actually runs them on a tool call was established by a run of the real tool, recorded with
89
+ its date and version in the [capability matrix](capability-matrix.md):
90
+
91
+ - OpenCode is `enforced`: its plugin refused `git push` to a protected branch and a native read of
92
+ a secrets file, while a read of an unprotected file stayed allowed.
93
+ - Codex is `enforced` only after a person trusts the hook on that machine. Codex silently skips a project hook nobody has trusted, so the same push ran
94
+ until the hook was trusted. See [Trust the Codex hook](#trust-the-codex-hook).
95
+ - Claude Code is `enforced`: its generated hook refused `git push` to a protected branch while
96
+ `git status` stayed allowed, and in an identical copy without the hook the same push ran.
97
+ Claude's own Read, Grep and Glob tools never reach the hook; the generated `Read` deny rules in
98
+ `.claude/settings.json` keep them off secrets (see
99
+ [Reading secrets and instances](safety-and-autonomy.md#reading-secrets-and-instances)).
100
+
101
+ Cursor and Grok Build are `generated`, and written only when `[surfaces] tools` lists them
102
+ (`npx --no cockpit tool add cursor --config <your cockpit.toml>`). Cockpit then writes rules,
103
+ skills, subagents, hooks, MCP and permission files for them (`rulesyncFeatures` in
104
+ [the harness registry](https://github.com/b0dea/cockpit/blob/main/packages/cockpit/src/surfaces/harness-registry.ts)), but nobody has
105
+ verified that either tool loads those files. Cockpit installs no guard hook for them, so their
106
+ guard-firing cells are `unavailable`.
107
+
108
+ ### Choose the tools
109
+
110
+ `[surfaces] tools` lists the agent tools `sync` writes and `check` compares; it defaults to the
111
+ tools whose guard is measured, `claudecode`, `codexcli` and `opencode`, and must name at least one
112
+ of them. A tool the list leaves out gets no files, and doctor and check give no advice about it.
113
+ `npx --no cockpit tool add <tool> --config <your cockpit.toml>` and `tool remove` edit only that
114
+ line (add `--dry-run` to preview). The next `sync` writes an added tool from the same sources as the
115
+ others; the files of a removed tool are listed for removal and deleted only after a person approves
116
+ the stale-removal digest with `sync --interactive`.
117
+
118
+ ### Trust the Codex hook
119
+
120
+ Codex runs the guard from `.codex/hooks.json` only after a person on that machine has trusted it,
121
+ and it skips an untrusted hook without saying so: every tool call then runs unguarded. Trust is
122
+ recorded per user in Codex's own configuration (`~/.codex/config.toml`, or `$CODEX_HOME`), keyed by
123
+ the hook's path and a hash of its command, so it is needed once per machine and again whenever
124
+ `sync` changes the hook. An agent cannot give it; a person does, once:
125
+
126
+ ```sh
127
+ codex -C <cockpit root>
128
+ ```
129
+
130
+ Start the interactive CLI (not `codex exec`) in the cockpit root, trust the folder if Codex asks,
131
+ and choose **Trust all and continue** when Codex shows **Hooks need review**; the `/hooks` view
132
+ inside a session does the same per hook. `cockpit doctor` and `cockpit check` read Codex's
133
+ configuration without changing it and report `CODEX_HOOK_UNTRUSTED` until every generated hook is
134
+ trusted, or when they cannot verify it. They report it only once Codex has run on the machine (a
135
+ Codex home exists); before that, no Codex session can skip the hook.
136
+
137
+ ### Session-start drift check
138
+
139
+ The generated `.claude/settings.json` and `.codex/hooks.json` also register a `SessionStart` hook that
140
+ runs `./node_modules/.bin/cockpit check --config cockpit.toml` in the cockpit root and prints the end of its report, so the
141
+ agent sees drift and the fix it names before it works; the *On drift* section of the cockpit-setup
142
+ procedure, which every shipped skill points to, says what to do with it. The hook never blocks a session. Codex runs it only once a person trusts it, like
143
+ the guard hook. OpenCode gets none: its plugins receive `session.created`, but no run has shown a plugin
144
+ putting text in the agent's context. The [capability matrix](capability-matrix.md) dates each
145
+ measurement.
146
+
147
+ ### Run cockpit outside the Codex sandbox
148
+
149
+ The generated `.codex/config.toml` runs Codex in its `workspace-write` sandbox with the sibling
150
+ checkouts as extra writable roots. Inside that sandbox Codex keeps `.git`, `.agents` and `.codex`
151
+ read-only and blocks cockpit's per-user state root and the Docker socket, so only `cockpit check`,
152
+ `cockpit sync --dry-run` and `--help` work there. Measured on 2026-11-02 with Codex 0.166.0's
153
+ `codex sandbox` and its built-in workspace profile, which agreed with a Codex session under the
154
+ generated configuration: `doctor`, `preflight`, `logs` and `work status` could not read cockpit's
155
+ state and `test-run` reported `DEGRADED`, while outside the sandbox they reported the real state and
156
+ the gate passed.
157
+
158
+ Run every other cockpit command outside the sandbox: from a terminal, or by approving Codex's
159
+ request to run it unsandboxed. That covers `init`, `sync`, `up`, `down`, `test-run`, `work` and
160
+ `git commit` in the cockpit. A `codex exec` run cannot ask, so a person runs those commands.
161
+
162
+ cockpit grants nothing more on purpose. Docker socket access controls the whole machine, which
163
+ would defeat the sandbox. The state root differs by host and user (see
164
+ [Clear cockpit state](troubleshooting.md#clear-cockpit-state)), so no committed path fits every
165
+ clone, and Codex keeps `.git`, `.agents` and `.codex` read-only inside every writable root.
166
+
167
+ ### Claude Code command rules
168
+
169
+ Claude Code's default mode runs no shell command without an allow rule, so a headless session was
170
+ refused even the `test-run` its own skill asks for. The generated `.claude/settings.json` therefore
171
+ allows, by prefix, the cockpit commands the shipped skills tell an agent to run and the guard
172
+ admits (see [Cockpit commands an agent can run](safety-and-autonomy.md#cockpit-commands-an-agent-can-run)),
173
+ spelled both as `npx --no cockpit <command>` and as `./node_modules/.bin/cockpit <command>`.
174
+ Person-only commands such as `sync`, `down` and `work accept` keep prompting. The guard hook still
175
+ runs first, and its ask or deny wins over a rule. Claude Code ignores a project's allow rules
176
+ until a person has trusted the workspace by starting Claude Code there once. Measured with Claude
177
+ Code 2.1.316 on 2026-11-02 beside a command with no rule.
178
+
179
+ OpenCode allows shell commands unless configured otherwise, and Codex runs them inside its sandbox
180
+ without asking, so cockpit writes no command rules for either.
181
+
182
+ ### OpenCode native reads
183
+
184
+ OpenCode's native `read`, `grep` and `glob` tools never reach a shell, so the generated plugin
185
+ restates each as the shell command that reads at least the same paths (`cat`, a recursive `grep`,
186
+ and `ls`) and asks the guard about that. A refusal names the restated command, so an agent can
187
+ narrow a search that would cover a secrets directory, a declared instance or an environment file
188
+ that is neither a declared template nor a documentation name such as `.env.example`. The generated
189
+ `opencode.jsonc` also denies OpenCode's `read` permission for every `.secrets` directory and each
190
+ declared instance, which holds even if the plugin does not load. It carries the `$schema` member
191
+ OpenCode would otherwise insert at every start, which made later checks report
192
+ `SURFACE_STATE_CONFLICT`.
193
+
194
+ ### Custom harnesses
195
+
196
+ A custom harness must declare exactly one row for every feature. Each row that is not
197
+ `unavailable` names a test date, the output spelling, a deliberately broken control, and the
198
+ module export that produces it. Cockpit checks the module's source and its result, so declaring a
199
+ capability without a recorded test result is not enough. For a row declared `enforced`, cockpit
200
+ also requires the named evidence file to match its declared SHA-256 before it runs the module, and
201
+ checks it again before publishing. That ties the declaration to one file; confirming real
202
+ enforcement still needs a separate paired test of the tool.
203
+
204
+ Custom modules must be self-contained: cockpit imports a module only if its bytes match the
205
+ declaration, and refuses relative imports of other files. The module runs in a worker that can
206
+ write only to its own temporary directory and cannot start child processes, worker threads or
207
+ native addons; if the installed Node.js cannot restrict filesystem access, cockpit refuses to run
208
+ it. These limits restrict ordinary file writes; they are not a sandbox against malicious code.
209
+
210
+ ### Guard adapters
211
+
212
+ The [capability matrix](capability-matrix.md) is the one record of each built-in harness's state,
213
+ generated from the shipped sources, with the date and tool version of every measurement. Those versions say nothing about the version you have installed. The checked-in guard
214
+ adapters (the [Claude](https://github.com/b0dea/cockpit/blob/main/packages/cockpit/surfaces/guards/claude.adapter.json),
215
+ [Codex](https://github.com/b0dea/cockpit/blob/main/packages/cockpit/surfaces/guards/codex.adapter.json) and
216
+ [OpenCode](https://github.com/b0dea/cockpit/blob/main/packages/cockpit/surfaces/guards/opencode.adapter.json) adapters) record how the
217
+ guard talks to each harness, as tested on an older version.
218
+
219
+ [Restriction expansion](https://github.com/b0dea/cockpit/blob/main/packages/cockpit/src/surfaces/restrictions.ts) checks the adapter's
220
+ recorded details but still emits `instructed`, including for native read-only settings; only a
221
+ dated run of the real tool, recorded in
222
+ [the harness registry](https://github.com/b0dea/cockpit/blob/main/packages/cockpit/src/surfaces/harness-registry.ts), changes a matrix
223
+ state. A harness without an adapter gets no control and is recorded as `unavailable`. Codex and OpenCode have no prompt tier, so "ask" decisions become denials; see
224
+ [Native adapter behavior](safety-and-autonomy.md#native-adapter-behavior).
225
+ [Rendering](https://github.com/b0dea/cockpit/blob/main/packages/cockpit/src/surfaces/render.ts) keeps those states, and
226
+ [selftest planning](https://github.com/b0dea/cockpit/blob/main/packages/cockpit/src/surfaces/selftest.ts) works out which
227
+ instruction-loading, guard-firing and per-skill tests to run for a candidate; run them with the
228
+ [selftest procedure](#skills-and-selftest-evidence). An old adapter record never upgrades a current
229
+ cell.
230
+
231
+ ## MCP servers and restrictions
232
+
233
+ `[mcp.approved]` is the shared allowlist. It maps each approved server name to the sha256 of the
234
+ declaration a human reviewed: its command, arguments, working directory relative to the cockpit,
235
+ and environment names. The declaration lives in a sibling's file, which an agent can edit, so a
236
+ server whose declaration changed after approval is no longer approved. A declared server absent
237
+ from the list, or whose digest differs, is rendered disabled for every configured harness (for
238
+ Claude Code through `disabledMcpjsonServers`, because it ignores `disabled` in `.mcp.json`), and
239
+ `sync` and `check` report `MCP_NOT_APPROVED` with the current digest to approve. A name on the allowlist without a
240
+ declaration reports `MCP_APPROVAL_UNKNOWN`. Cockpit rejects conflicting commands for one server,
241
+ credential-like arguments, environment values that are not same-name references, and working
242
+ directories outside the declared sibling. Each harness starts the generated wrapper as
243
+ `.cockpit/mcp/<id>.sh` relative to the directory the agent was launched in, so it runs only when
244
+ the agent was started in the cockpit root, as the guard hooks already require. The wrapper changes
245
+ to its sibling by a path relative to that root, resolved physically and never through `CDPATH`, so
246
+ the committed files are the same in every clone. Wrappers start with an empty
247
+ environment and pass `PATH`, the same non-secret variables product test stages receive (`HOME`,
248
+ `USER`, `LOGNAME`, `TMPDIR`, `LANG`, `LC_ALL`, `LC_CTYPE`, `TZ`) and the declared environment
249
+ names.
250
+
251
+ Browser transport is published only for harnesses that can use it. A harness with no applicable
252
+ MCP server receives no MCP-only output; its instructions, skills and permissions still publish.
253
+ Verify the result with `./node_modules/.bin/cockpit check --config cockpit.toml --json` after
254
+ `sync`.
255
+
256
+ Restriction policy comes from `[guards]`: cockpit expands one shared guard through a tested adapter
257
+ for each harness, and a harness event with no adapter stays `unavailable`. Read-only subagent
258
+ support is reported on its own, because an instruction-only restriction is weaker than a native
259
+ tool restriction.
260
+
261
+ ## Sibling projection and standing cost
262
+
263
+ Cockpit reads each sibling's guides (`sibling.guides`, by default **CLAUDE.md** and **AGENTS.md**)
264
+ from its declared root and copies them into its region of the root **AGENTS.md**, after its own
265
+ instructions. Every agent tool reads that file, Claude Code through the `@AGENTS.md` import in
266
+ **CLAUDE.md**, so each tool starts with the same sibling instructions. Copying is the one route that
267
+ loaded in Claude Code, Codex and OpenCode alike: a symlinked guide imported from **CLAUDE.md**, an
268
+ extra directory handed to Claude Code or Codex, and a line telling Codex to read the guide each
269
+ left Claude Code or Codex without it; the [capability matrix](capability-matrix.md) has the dated
270
+ runs. Each copy starts with a heading naming the sibling and a comment recording the guide and the
271
+ SHA-256 of the text copied. A copy leaves out the marked block `setup --write-instruction-pointers`
272
+ appended to the guide, and a **CLAUDE.md** line importing the sibling's own **AGENTS.md** when that
273
+ file is copied as well. Sync refuses a guide that changes while it is read, resolves outside its
274
+ root, or contains cockpit's own instruction region or owner markers.
275
+
276
+ A copy goes stale when the sibling's guide changes: `check` and `preflight` then report
277
+ `GENERATED_ARTIFACT_DRIFT` naming each out-of-date `<sibling>/<guide>`, and a person runs `sync` and
278
+ commits **AGENTS.md**. That is deliberate. An agent editing a sibling's guide cannot change what
279
+ every later agent session in the cockpit loads until a person has reviewed the new text, the same
280
+ review a change to **CLAUDE.md**'s imports gets. A Claude Code `@` import inside a copied guide
281
+ resolves from the cockpit root, not the sibling, and no other tool follows it, so keep shared
282
+ guides free of them.
283
+
284
+ Codex sibling grants are `sandbox_workspace_write.writable_roots` entries under
285
+ `sandbox_mode = "workspace-write"`. Codex resolves a relative root from `.codex/`, so cockpit writes
286
+ each one relative to that directory (`../../api` for a sibling at `../api`) and clones do not
287
+ drift, and emits no competing permission profile, because Codex ignores one when the
288
+ workspace-write settings are present. This is generated configuration, not a measured claim that
289
+ Codex enforces it; run the [selftest procedure](#skills-and-selftest-evidence) before
290
+ promoting that matrix cell.
291
+
292
+ OpenCode matches `external_directory` against absolute paths only and has no token for the
293
+ project root, so the committed pattern is `{file:.cockpit/local/opencode-grant-<slug>}/**`: OpenCode
294
+ substitutes the absolute sibling directory that `sync` writes to that machine-local, ignored file,
295
+ and refuses to start, naming the file, until `sync` has run on the machine.
296
+
297
+ The `[cockpit].guide_cap` limit applies to always-loaded guidance, copied sibling guides included;
298
+ going over it makes `sync`, `check` and `preflight` report `GUIDE_CAP_EXCEEDED` with the measured
299
+ lines and the cap. The same code reports cockpit's region of **AGENTS.md** passing 32768 bytes,
300
+ because Codex silently drops the rest of a longer project **AGENTS.md**. Cockpit reports the line cost per
301
+ harness only when it has a dated test of how that harness loads guidance; without one the cost is
302
+ `unavailable`, not zero. When a harness loads every rule regardless of scope, scoped text still
303
+ counts toward the total.
304
+
305
+ ## Skills and selftest evidence
306
+
307
+ Shipped skills have small entry points and shared procedures. Each skill declares its trigger,
308
+ the equivalent tool name in each harness, the cockpit commands it may run, what it changes, what it
309
+ must not do, its review requirements and a line cap. The renderer refuses embedded decision logic,
310
+ undeclared commands, missing tool equivalents, missing procedures, duplicate names, and skills over
311
+ the always-loaded size limit. Codex also receives its generated skill sidecar.
312
+
313
+ `selftest` runs each tool against a probe-specification file: one row per built-in tool cell the
314
+ generated manifest expects evidence for (each built-in tool's instruction loading, guard firing and
315
+ the parity of each shipped skill). The file is tied to the current `cockpit.toml` digest and
316
+ generated manifest, so it goes stale whenever either changes.
317
+
318
+ A custom harness cell gets no row. `selftest` runs only a tool it found on `PATH` and you approved
319
+ by digest, and a custom harness has no such executable, so a row for it could only be ignored.
320
+ Writing the file warns `SELFTEST_CUSTOM_PROBE_UNSUPPORTED` for each such cell, `selftest` records
321
+ it `human_needed` with `enforcement_probe_required`, and a custom row added by hand is refused.
322
+ Measure a custom capability yourself and record it as its `state` and `measured_on`.
323
+
324
+ 1. After `sync`, write the file to a new path. It refuses a path that already exists, so a file you
325
+ have filled in is never overwritten:
326
+
327
+ ```sh
328
+ npx --no cockpit selftest --config ./cockpit.toml \
329
+ --write-probe-specifications ./.cockpit/local/probe-specifications.json
330
+ ```
331
+
332
+ It prints which rows it wrote and where each value came from. The generated manifest decides
333
+ `harness`, `capability`, the skill in `sample` and `unavailableCode`. cockpit fills
334
+ `versionCommand` and `helpCommand` with the tool's `--version` and `--help`.
335
+
336
+ After a change to `cockpit.toml` or the generated manifest, your filled file is stale. Write
337
+ the new file from it so the probes you wrote are kept:
338
+
339
+ ```sh
340
+ npx --no cockpit selftest --config ./cockpit.toml \
341
+ --write-probe-specifications ./.cockpit/local/probe-specifications-2.json \
342
+ --probe-specifications ./.cockpit/local/probe-specifications.json
343
+ ```
344
+
345
+ Each complete row whose cell still exists is copied as it was, and the output says how many.
346
+ Rows for new or changed cells, and rows you left partly `null`, start over with `null`s.
347
+ 2. Replace every `null` in the file. Nothing in the manifest says how a given tool version can be
348
+ made to load a control file and report what it did, so these values come from you:
349
+ - `invocation`: the arguments, starting with `{executable}` like `versionCommand`, with
350
+ exactly one `{control}`. cockpit
351
+ replaces `{control}` with the path of a control file it writes under `.cockpit/local/probes/`:
352
+ the generated file under test, or a deliberately broken copy.
353
+ - `candidateCode` and `brokenCode`: codes you choose (capital letters, digits and underscores,
354
+ starting with a letter) that the tool prints as a line of their own. With the broken control it must
355
+ exit non-zero and print `brokenCode`. With the candidate it must exit 0 and print
356
+ `candidateCode` (instructed), or, for guard firing, exit non-zero and print it (enforced), or
357
+ print `unavailableCode` (unavailable). Any other result refuses the whole run.
358
+ - `sample.features` on skill-parity rows: which of `name`, `trigger`, `body-load`, `tools` and
359
+ `non-goals` your invocation exercises.
360
+
361
+ `selftest` refuses a file that still has a `null` and lists the rows.
362
+ 3. In a terminal outside CI, outside an agent session, run:
363
+
364
+ ```sh
365
+ npx --no cockpit selftest --interactive --config ./cockpit.toml \
366
+ --probe-specifications ./.cockpit/local/probe-specifications.json
367
+ ```
368
+
369
+ It first runs the read-only generated-file check and refuses a file that is missing,
370
+ malformed, stale, or does not match the current source and manifest. It then shows the file's
371
+ canonical path, its SHA-256, the source and manifest digests it is tied to, and each exact
372
+ invocation, version and help command. Compare the SHA-256 with `shasum -a 256 <file>` and type
373
+ it at the prompt. For each tool it then shows the absolute path and SHA-256 of the executable it
374
+ found on `PATH`; type that SHA-256 to let it run. Anything else leaves that cell `human_needed`
375
+ and it asks again at the tool's next cell. Approval lasts only for that run. Without `--interactive`, or in CI or JSON
376
+ mode, nothing in the file runs.
377
+
378
+ For each approved built-in tool, `selftest` runs the version and help commands, then the invocation
379
+ with the broken control and with the candidate, and records each event. The probes inherit only
380
+ `PATH`, `HOME`, `USER`, `LOGNAME`, `TMPDIR`, `LANG`, `LC_ALL`, `LC_CTYPE` and `TZ`, so a tool that
381
+ keeps its sign-in under `HOME` finds it. No other variable reaches the probe, so a tool signed in
382
+ only through an environment token reports that it is not signed in; that cell stays `human_needed`
383
+ with `authentication_required`.
384
+
385
+ Some cells stay `human_needed` regardless:
386
+
387
+ - a custom harness cell, which has no probe row (see above);
388
+ - Claude Code and Codex skill reviews, until the official-authoring or native-diagnostics results
389
+ are attached.
390
+
391
+ Repository tests and generated records do not promote those native or human rows.
392
+
393
+ Cockpit limits the size of legacy adapter records, command vectors and captured output before
394
+ parsing them; the [validator](https://github.com/b0dea/cockpit/blob/main/packages/cockpit/libexec/validate-harness-evidence.mjs) holds the
395
+ current limits. It refuses changed files and files that are not regular. These records keep their
396
+ original capability strength; passing the validator does not promote a native capability.
397
+
398
+ ## Upgrade cockpit
399
+
400
+ An upgrade replaces the generated files that guard and instruct every agent, so a person reads
401
+ what `sync` would change before it writes. One command does the whole move:
402
+
403
+ ```sh
404
+ npx --no cockpit upgrade --config cockpit.toml # latest published release
405
+ npx --no cockpit upgrade 1.4.0 --config cockpit.toml # a named version, including an older one
406
+ npx --no cockpit upgrade --config cockpit.toml --dry-run # resolve the target, print the commands, run nothing
407
+ ```
408
+
409
+ `upgrade` resolves the target (`npm view @b00dea/cockpit version`), refuses one that is not newer
410
+ than the installed version unless you name it, detects the package manager from the one lockfile at
411
+ the cockpit root (`package-lock.json`, `pnpm-lock.yaml` or `yarn.lock`), installs the exact version as
412
+ a dev dependency, then runs `npx --no cockpit sync --config <path>` in a new process so the new
413
+ version renders. Sync's output and exit code pass through, so its own decisions stand: it removes
414
+ stale generated files under `[autonomy] stale_delete = "agent"`, and otherwise asks for the digest a
415
+ person types with `sync --interactive` in a terminal. It ends by printing the `Upgrade:`
416
+ lines from the installed `CHANGELOG.md` between the two versions (a line there names a step `sync`
417
+ does not do), or the npm page when the package has no changelog.
418
+
419
+ An agent may run `upgrade` exactly where it may run a writing `sync`: under `[autonomy] sync =
420
+ "agent"`, the default. Under `person` or `ci` the guard asks, as it does for `sync`, and the sync child
421
+ refuses outside CI under `ci`. `upgrade --dry-run` writes nothing, so it is never gated. Until `sync` finishes, the guard holds every agent tool call,
422
+ because it trusts only the cockpit it was generated for. A built-in that one of your overlays replaces and that the new release
423
+ changed is reported as `OVERRIDDEN_CORE_CHANGED`: review the new built-in against your override
424
+ before updating its recorded hash. Then review `git diff` and commit `package.json`, the lockfile and
425
+ the regenerated files together.
426
+
427
+ Dependabot and Renovate can bump the exact pin on their own. The `cockpit-check` CI action then reports
428
+ drift until someone runs `npx --no cockpit sync --config cockpit.toml` (or `upgrade <version>`) and
429
+ commits the regenerated files.
430
+
431
+ By hand: `npm install --save-dev --save-exact @b00dea/cockpit@<version>` (`npm update` does not move an
432
+ exact pin), read `./node_modules/@b00dea/cockpit/CHANGELOG.md`, preview with
433
+ `npx --no cockpit sync --config cockpit.toml --dry-run`, then run `sync` in a terminal.
@@ -0,0 +1,76 @@
1
+ # Joining a team's cockpit
2
+
3
+ This guide is for a developer who has cloned a cockpit that a team already committed, with its
4
+ `cockpit.toml` and generated files. You create this machine's local state, then confirm that the
5
+ committed files did not change.
6
+
7
+ ## Install the team's exact version
8
+
9
+ From the cockpit root, install the lockfile without changing it:
10
+
11
+ ```sh
12
+ npm ci
13
+ ```
14
+
15
+ The root `package.json` pins `@b00dea/cockpit` exactly, because different cockpit versions can render
16
+ different guards and teammates would keep reporting each other's output as drift. `cockpit check`
17
+ refuses a running version that differs from the pin and prints the
18
+ `npm install --save-dev --save-exact` command that realigns them. Do not replace the pin with a range.
19
+
20
+ ## Prepare this checkout
21
+
22
+ Run the committed scripts:
23
+
24
+ ```sh
25
+ npm run cockpit:setup
26
+ npm run cockpit:sync
27
+ npm run cockpit:check
28
+ ```
29
+
30
+ - `setup` clones or verifies the declared sibling repositories.
31
+ - `sync` checks this checkout, writes its machine identity under `.cockpit/local/`, and refreshes
32
+ the generated files from `cockpit.toml`. Committed files do not depend on where you cloned: harness
33
+ directory grants are relative to the cockpit root, and Docker labels that carry the checkout
34
+ path reach Compose only when a command runs.
35
+ - `check` confirms the generated files match `cockpit.toml`.
36
+
37
+ For Codex, the relative grants go to `sandbox_workspace_write.writable_roots` with
38
+ `sandbox_mode = "workspace-write"`, and cockpit publishes no separate permission profile because
39
+ Codex gives the workspace-write settings precedence. Run `npm run cockpit:sync` after changing
40
+ sibling declarations to regenerate the list.
41
+
42
+ Two things stay per machine:
43
+
44
+ - **Codex hook trust.** Codex silently skips a project hook nobody has trusted on that machine,
45
+ and `check` reports `CODEX_HOOK_UNTRUSTED`, once Codex has run on the machine, until you
46
+ [trust the Codex hook](harness-surfaces.md#trust-the-codex-hook).
47
+ - **Runtime measurements.** Each machine measures its own container runtime once before its first
48
+ `up`; see [Measure the container runtime](environment.md#measure-the-container-runtime).
49
+
50
+ ### The `cockpit:ignore` region
51
+
52
+ The root `.gitignore` has a marked `cockpit:ignore` region for installed dependencies,
53
+ machine-local state, secret resolver material, and any sibling checkout below the cockpit root.
54
+ `init`, or the first `sync` of a hand-written configuration, creates it and leaves every line
55
+ outside it alone. Its start marker records a digest, so `sync` rewrites a region that sibling
56
+ changes made stale but refuses one edited by hand; `check` reports either without writing.
57
+
58
+ A sibling with `acquire = "none"` stays visible, so the cockpit can track local data, unless its
59
+ directory is a Git repository (such as one `sibling add --create` made), which is ignored like a
60
+ cloned checkout. Sibling directories are written as literal ignore paths, so wildcard-shaped names
61
+ match nothing else. A `siblings_root` containing a line break or NUL is refused before anything
62
+ changes, because `.gitignore` cannot represent it.
63
+
64
+ ## Verify a clean join
65
+
66
+ After `check` succeeds, confirm that setup did not change team-owned bytes:
67
+
68
+ ```sh
69
+ git status --short
70
+ ```
71
+
72
+ It should print nothing. If it shows generated drift, confirm `npm ci` installed the exact pinned
73
+ version. If `sync` changed only the `.gitignore` block, a declared sibling differs on this machine:
74
+ a local repository with no remote is ignored only where it exists, because nothing can clone it
75
+ here. Discard the change with `git restore .gitignore`; the block settles once whoever created that
76
+ repository publishes it and records the remote with `sibling add <slug> --remote <url>`.
@@ -0,0 +1,49 @@
1
+ # Runtime, deprecation, and migration policy
2
+
3
+ This page is for people choosing or upgrading cockpit: which runtimes are supported, how much
4
+ notice a breaking change gets, and what a migration note contains.
5
+
6
+ ## Runtime support
7
+
8
+ The supported Node.js versions are the ones in the `engines` field of the
9
+ [package manifest](https://github.com/b0dea/cockpit/blob/main/packages/cockpit/package.json). The launcher refuses any other version with
10
+ [COCKPIT_NODE_VERSION_UNSUPPORTED](https://github.com/b0dea/cockpit/blob/main/packages/cockpit/bin/cockpit.mjs) before compiled code loads.
11
+ Environment commands also need Git and, for the stack, Docker with Compose; see the
12
+ [prerequisites](getting-started.md#install-cockpit).
13
+
14
+ CI tests that range:
15
+
16
+ - on every merge to main, the full suite on macOS and Linux at the lowest supported version, and a
17
+ compatibility subset (launcher, package metadata and runtime probe tests) on Linux at each other
18
+ supported line;
19
+ - weekly, the full suite on Linux at the newest supported line.
20
+
21
+ Fixes land on the latest released minor only; older minors are deprecated when a new minor ships.
22
+ Pin an exact version in each consumer lockfile and review an upgrade before applying its generated
23
+ changes.
24
+
25
+ The deprecation policy below applies to published releases. While the major version is 0, a
26
+ minor release may still carry a breaking change; it still ships a migration note.
27
+
28
+ ## Deprecation
29
+
30
+ A public command, option, configuration field, generated path, diagnostic contract or extension
31
+ seam gets at least one minor release of warning before removal. The warning names the replacement
32
+ and the release in which removal can happen. A security fix may refuse unsafe behaviour
33
+ immediately, but still provides the safest migration available.
34
+
35
+ Dropping a supported Node.js release line before its end of life is a major change.
36
+
37
+ The generated [CLI reference](cli-reference.md), [configuration reference](configuration-reference.md),
38
+ [capability matrix](capability-matrix.md) and [Troubleshooting](troubleshooting.md) describe the
39
+ installed version only; they promise nothing about later releases beyond this policy.
40
+
41
+ ## Migration
42
+
43
+ Every breaking change ships a migration note in the [changelog](https://github.com/b0dea/cockpit/blob/main/packages/cockpit/CHANGELOG.md)
44
+ for whoever performs the upgrade: what changed, the observable failure or diagnostic, the exact
45
+ replacement, and any rollback boundary. When the edit is mechanical, the release includes a codemod
46
+ or script rather than prose.
47
+
48
+ To upgrade, run `npx --no cockpit upgrade --config cockpit.toml`: it moves the exact pin and applies
49
+ the regenerated files with `sync`, as [Upgrade cockpit](harness-surfaces.md#upgrade-cockpit) describes.