@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.
- package/CHANGELOG.md +375 -0
- package/LICENSE +21 -0
- package/README.md +22 -2
- package/bin/cockpit.mjs +33 -0
- package/cockpit.schema.json +2574 -0
- package/dist/autonomy.d.ts +44 -0
- package/dist/autonomy.js +156 -0
- package/dist/bounded-read.d.ts +14 -0
- package/dist/bounded-read.js +42 -0
- package/dist/browser/commands.d.ts +62 -0
- package/dist/browser/commands.js +349 -0
- package/dist/browser/package-paths.d.ts +1 -0
- package/dist/browser/package-paths.js +6 -0
- package/dist/browser/proxy.d.ts +22 -0
- package/dist/browser/proxy.js +37 -0
- package/dist/browser/runtime.d.ts +117 -0
- package/dist/browser/runtime.js +183 -0
- package/dist/browser/surfaces.d.ts +141 -0
- package/dist/browser/surfaces.js +556 -0
- package/dist/browser/ui-gate.d.ts +15 -0
- package/dist/browser/ui-gate.js +18 -0
- package/dist/cli-guard.d.ts +5 -0
- package/dist/cli-guard.js +71 -0
- package/dist/cli-main.d.ts +139 -0
- package/dist/cli-main.js +1405 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +16 -0
- package/dist/command-table.d.ts +113 -0
- package/dist/command-table.js +512 -0
- package/dist/config/load.d.ts +171 -0
- package/dist/config/load.js +345 -0
- package/dist/config/sibling-toml.d.ts +48 -0
- package/dist/config/sibling-toml.js +160 -0
- package/dist/config/surface-tools-toml.d.ts +9 -0
- package/dist/config/surface-tools-toml.js +37 -0
- package/dist/config/verified-write.d.ts +43 -0
- package/dist/config/verified-write.js +89 -0
- package/dist/diagnostics.d.ts +26 -0
- package/dist/diagnostics.js +335 -0
- package/dist/emit.d.ts +22 -0
- package/dist/emit.js +43 -0
- package/dist/entrypoint-kinds.d.ts +3 -0
- package/dist/entrypoint-kinds.js +11 -0
- package/dist/environment/application/destructive.d.ts +6 -0
- package/dist/environment/application/destructive.js +425 -0
- package/dist/environment/application/doctor.d.ts +89 -0
- package/dist/environment/application/doctor.js +235 -0
- package/dist/environment/application/guard.d.ts +43 -0
- package/dist/environment/application/guard.js +622 -0
- package/dist/environment/application/health.d.ts +134 -0
- package/dist/environment/application/health.js +379 -0
- package/dist/environment/application/lifecycle-context.d.ts +228 -0
- package/dist/environment/application/lifecycle-context.js +154 -0
- package/dist/environment/application/lifecycle-state.d.ts +25 -0
- package/dist/environment/application/lifecycle-state.js +201 -0
- package/dist/environment/application/lifecycle.d.ts +17 -0
- package/dist/environment/application/lifecycle.js +729 -0
- package/dist/environment/application/logs.d.ts +45 -0
- package/dist/environment/application/logs.js +127 -0
- package/dist/environment/application/setup.d.ts +129 -0
- package/dist/environment/application/setup.js +741 -0
- package/dist/environment/application/shared.d.ts +11 -0
- package/dist/environment/application/shared.js +61 -0
- package/dist/environment/claims.d.ts +389 -0
- package/dist/environment/claims.js +1709 -0
- package/dist/environment/codex-hook-trust.d.ts +11 -0
- package/dist/environment/codex-hook-trust.js +185 -0
- package/dist/environment/compose-environment.d.ts +1 -0
- package/dist/environment/compose-environment.js +6 -0
- package/dist/environment/compose-ownership.d.ts +21 -0
- package/dist/environment/compose-ownership.js +117 -0
- package/dist/environment/compose-topology.d.ts +117 -0
- package/dist/environment/compose-topology.js +413 -0
- package/dist/environment/contract.d.ts +489 -0
- package/dist/environment/contract.js +761 -0
- package/dist/environment/declaration.d.ts +14 -0
- package/dist/environment/declaration.js +39 -0
- package/dist/environment/destructive-composition.d.ts +29 -0
- package/dist/environment/destructive-composition.js +333 -0
- package/dist/environment/docker-daemon.d.ts +30 -0
- package/dist/environment/docker-daemon.js +78 -0
- package/dist/environment/docker-endpoint.d.ts +10 -0
- package/dist/environment/docker-endpoint.js +19 -0
- package/dist/environment/env-schema-observation.d.ts +46 -0
- package/dist/environment/env-schema-observation.js +241 -0
- package/dist/environment/evidence.d.ts +136 -0
- package/dist/environment/evidence.js +437 -0
- package/dist/environment/executable.d.ts +26 -0
- package/dist/environment/executable.js +167 -0
- package/dist/environment/generated-application/authorities.d.ts +5 -0
- package/dist/environment/generated-application/authorities.js +61 -0
- package/dist/environment/generated-application/bootstrap-skill.d.ts +16 -0
- package/dist/environment/generated-application/bootstrap-skill.js +328 -0
- package/dist/environment/generated-application/check.d.ts +13 -0
- package/dist/environment/generated-application/check.js +189 -0
- package/dist/environment/generated-application/custom-surface.d.ts +26 -0
- package/dist/environment/generated-application/custom-surface.js +289 -0
- package/dist/environment/generated-application/prepare.d.ts +29 -0
- package/dist/environment/generated-application/prepare.js +276 -0
- package/dist/environment/generated-application/publication.d.ts +33 -0
- package/dist/environment/generated-application/publication.js +547 -0
- package/dist/environment/generated-application/shared.d.ts +484 -0
- package/dist/environment/generated-application/shared.js +349 -0
- package/dist/environment/generated-application/surface-observation.d.ts +4 -0
- package/dist/environment/generated-application/surface-observation.js +69 -0
- package/dist/environment/generated-application/surface-outputs.d.ts +71 -0
- package/dist/environment/generated-application/surface-outputs.js +389 -0
- package/dist/environment/generated-application/surfaces.d.ts +3 -0
- package/dist/environment/generated-application/surfaces.js +699 -0
- package/dist/environment/generated-application/sync.d.ts +6 -0
- package/dist/environment/generated-application/sync.js +109 -0
- package/dist/environment/git-observation.d.ts +183 -0
- package/dist/environment/git-observation.js +544 -0
- package/dist/environment/health-composition.d.ts +11 -0
- package/dist/environment/health-composition.js +628 -0
- package/dist/environment/host-observation.d.ts +56 -0
- package/dist/environment/host-observation.js +52 -0
- package/dist/environment/identity.d.ts +48 -0
- package/dist/environment/identity.js +85 -0
- package/dist/environment/init-application.d.ts +308 -0
- package/dist/environment/init-application.js +697 -0
- package/dist/environment/install-policy-observation.d.ts +71 -0
- package/dist/environment/install-policy-observation.js +284 -0
- package/dist/environment/install-policy.d.ts +48 -0
- package/dist/environment/install-policy.js +96 -0
- package/dist/environment/instance.d.ts +33 -0
- package/dist/environment/instance.js +122 -0
- package/dist/environment/instruction-pointer.d.ts +19 -0
- package/dist/environment/instruction-pointer.js +144 -0
- package/dist/environment/lifecycle-composition.d.ts +29 -0
- package/dist/environment/lifecycle-composition.js +675 -0
- package/dist/environment/lifecycle-stage.d.ts +115 -0
- package/dist/environment/lifecycle-stage.js +398 -0
- package/dist/environment/lifecycle.d.ts +75 -0
- package/dist/environment/lifecycle.js +354 -0
- package/dist/environment/logs.d.ts +132 -0
- package/dist/environment/logs.js +519 -0
- package/dist/environment/observations.d.ts +46 -0
- package/dist/environment/observations.js +344 -0
- package/dist/environment/operator-application.d.ts +50 -0
- package/dist/environment/operator-application.js +155 -0
- package/dist/environment/ports.d.ts +182 -0
- package/dist/environment/ports.js +1205 -0
- package/dist/environment/posture-observation.d.ts +68 -0
- package/dist/environment/posture-observation.js +253 -0
- package/dist/environment/read-composition.d.ts +27 -0
- package/dist/environment/read-composition.js +352 -0
- package/dist/environment/readiness-composition.d.ts +38 -0
- package/dist/environment/readiness-composition.js +130 -0
- package/dist/environment/reclaim.d.ts +333 -0
- package/dist/environment/reclaim.js +1835 -0
- package/dist/environment/repository-identity.d.ts +13 -0
- package/dist/environment/repository-identity.js +108 -0
- package/dist/environment/runtime-measurement-record.d.ts +38 -0
- package/dist/environment/runtime-measurement-record.js +111 -0
- package/dist/environment/runtime-measurement.d.ts +27 -0
- package/dist/environment/runtime-measurement.js +224 -0
- package/dist/environment/runtime-probe-residue.d.ts +43 -0
- package/dist/environment/runtime-probe-residue.js +148 -0
- package/dist/environment/runtime-probe.d.ts +72 -0
- package/dist/environment/runtime-probe.js +725 -0
- package/dist/environment/runtime.d.ts +505 -0
- package/dist/environment/runtime.js +2335 -0
- package/dist/environment/seed.d.ts +16 -0
- package/dist/environment/seed.js +43 -0
- package/dist/environment/selftest-application.d.ts +86 -0
- package/dist/environment/selftest-application.js +713 -0
- package/dist/environment/sensitive.d.ts +3 -0
- package/dist/environment/sensitive.js +48 -0
- package/dist/environment/setup-observation.d.ts +62 -0
- package/dist/environment/setup-observation.js +1473 -0
- package/dist/environment/setup.d.ts +43 -0
- package/dist/environment/setup.js +176 -0
- package/dist/environment/sibling-instructions.d.ts +33 -0
- package/dist/environment/sibling-instructions.js +224 -0
- package/dist/environment/sibling-registration.d.ts +45 -0
- package/dist/environment/sibling-registration.js +538 -0
- package/dist/environment/state.d.ts +371 -0
- package/dist/environment/state.js +2013 -0
- package/dist/environment/templates.d.ts +140 -0
- package/dist/environment/templates.js +685 -0
- package/dist/environment/tool-registration.d.ts +9 -0
- package/dist/environment/tool-registration.js +96 -0
- package/dist/environment/upgrade-application.d.ts +19 -0
- package/dist/environment/upgrade-application.js +175 -0
- package/dist/environment-exec/execute.d.ts +102 -0
- package/dist/environment-exec/execute.js +1175 -0
- package/dist/environment-exec/libexec-program.d.ts +6 -0
- package/dist/environment-exec/libexec-program.js +22 -0
- package/dist/environment-exec/verified-digest.d.ts +4 -0
- package/dist/environment-exec/verified-digest.js +16 -0
- package/dist/exact-keys.d.ts +7 -0
- package/dist/exact-keys.js +15 -0
- package/dist/fix-catalogue.d.ts +32 -0
- package/dist/fix-catalogue.js +60 -0
- package/dist/freshness.d.ts +29 -0
- package/dist/freshness.js +75 -0
- package/dist/generated-environment/adopt.d.ts +16 -0
- package/dist/generated-environment/adopt.js +275 -0
- package/dist/generated-environment/command.d.ts +47 -0
- package/dist/generated-environment/command.js +75 -0
- package/dist/generated-environment/transaction.d.ts +186 -0
- package/dist/generated-environment/transaction.js +1770 -0
- package/dist/grading/evaluate.d.ts +71 -0
- package/dist/grading/evaluate.js +403 -0
- package/dist/grading/grade.d.ts +33 -0
- package/dist/grading/grade.js +57 -0
- package/dist/guards/evaluator.d.ts +113 -0
- package/dist/guards/evaluator.js +1226 -0
- package/dist/guards/harness-adapter.d.ts +17 -0
- package/dist/guards/harness-adapter.js +57 -0
- package/dist/guards/host.d.ts +8 -0
- package/dist/guards/host.js +10 -0
- package/dist/guards/invocation-parser.d.ts +66 -0
- package/dist/guards/invocation-parser.js +595 -0
- package/dist/guards/local-identity.d.ts +40 -0
- package/dist/guards/local-identity.js +123 -0
- package/dist/guards/policy-pin.d.ts +13 -0
- package/dist/guards/policy-pin.js +175 -0
- package/dist/guards/protected-locations.d.ts +62 -0
- package/dist/guards/protected-locations.js +461 -0
- package/dist/guards/read-only.d.ts +37 -0
- package/dist/guards/read-only.js +315 -0
- package/dist/init/command.d.ts +40 -0
- package/dist/init/command.js +310 -0
- package/dist/init/derive.d.ts +51 -0
- package/dist/init/derive.js +715 -0
- package/dist/init/draft.d.ts +138 -0
- package/dist/init/draft.js +1205 -0
- package/dist/init/render.d.ts +35 -0
- package/dist/init/render.js +82 -0
- package/dist/init/scaffold.d.ts +53 -0
- package/dist/init/scaffold.js +121 -0
- package/dist/invocation.d.ts +13 -0
- package/dist/invocation.js +20 -0
- package/dist/package-metadata.d.ts +9 -0
- package/dist/package-metadata.js +19 -0
- package/dist/readiness.d.ts +53 -0
- package/dist/readiness.js +88 -0
- package/dist/references/named.d.ts +24 -0
- package/dist/references/named.js +27 -0
- package/dist/refusal.d.ts +15 -0
- package/dist/refusal.js +7 -0
- package/dist/registry-derivation.d.ts +31 -0
- package/dist/registry-derivation.js +32 -0
- package/dist/registry-resolve/command.d.ts +47 -0
- package/dist/registry-resolve/command.js +226 -0
- package/dist/registry-resolve/registry.d.ts +68 -0
- package/dist/registry-resolve/registry.js +292 -0
- package/dist/registry-resolve/render-shell.d.ts +18 -0
- package/dist/registry-resolve/render-shell.js +36 -0
- package/dist/repair.d.ts +29 -0
- package/dist/repair.js +8 -0
- package/dist/schema-json.d.ts +1 -0
- package/dist/schema-json.js +177 -0
- package/dist/schema.d.ts +1322 -0
- package/dist/schema.js +934 -0
- package/dist/setup/command.d.ts +4 -0
- package/dist/setup/command.js +4 -0
- package/dist/sha256.d.ts +1 -0
- package/dist/sha256.js +4 -0
- package/dist/surfaces/adoption.d.ts +41 -0
- package/dist/surfaces/adoption.js +217 -0
- package/dist/surfaces/consumer-instructions.d.ts +20 -0
- package/dist/surfaces/consumer-instructions.js +43 -0
- package/dist/surfaces/contract.d.ts +42 -0
- package/dist/surfaces/contract.js +169 -0
- package/dist/surfaces/core-declarations.d.ts +24 -0
- package/dist/surfaces/core-declarations.js +79 -0
- package/dist/surfaces/development-markers.d.ts +1 -0
- package/dist/surfaces/development-markers.js +18 -0
- package/dist/surfaces/generator-adapter.d.ts +71 -0
- package/dist/surfaces/generator-adapter.js +809 -0
- package/dist/surfaces/harness-registry.d.ts +180 -0
- package/dist/surfaces/harness-registry.js +117 -0
- package/dist/surfaces/mcp.d.ts +95 -0
- package/dist/surfaces/mcp.js +186 -0
- package/dist/surfaces/merge.d.ts +30 -0
- package/dist/surfaces/merge.js +105 -0
- package/dist/surfaces/ownership.d.ts +190 -0
- package/dist/surfaces/ownership.js +795 -0
- package/dist/surfaces/projection.d.ts +136 -0
- package/dist/surfaces/projection.js +681 -0
- package/dist/surfaces/render.d.ts +118 -0
- package/dist/surfaces/render.js +633 -0
- package/dist/surfaces/restrictions.d.ts +130 -0
- package/dist/surfaces/restrictions.js +447 -0
- package/dist/surfaces/selftest.d.ts +162 -0
- package/dist/surfaces/selftest.js +393 -0
- package/dist/surfaces/skill-contract.d.ts +85 -0
- package/dist/surfaces/skill-contract.js +449 -0
- package/dist/surfaces/sync.d.ts +57 -0
- package/dist/surfaces/sync.js +164 -0
- package/dist/team-metadata.d.ts +41 -0
- package/dist/team-metadata.js +512 -0
- package/dist/testing/gates.d.ts +91 -0
- package/dist/testing/gates.js +182 -0
- package/dist/testing/hooks.d.ts +59 -0
- package/dist/testing/hooks.js +139 -0
- package/dist/testing/verdict.d.ts +29 -0
- package/dist/testing/verdict.js +62 -0
- package/dist/work-orders/application.d.ts +99 -0
- package/dist/work-orders/application.js +383 -0
- package/dist/work-orders/composition.d.ts +124 -0
- package/dist/work-orders/composition.js +1010 -0
- package/dist/work-orders/contract.d.ts +61 -0
- package/dist/work-orders/contract.js +122 -0
- package/dist/work-orders/store.d.ts +158 -0
- package/dist/work-orders/store.js +197 -0
- package/docs/README.md +65 -0
- package/docs/architecture.md +136 -0
- package/docs/capability-matrix.md +50 -0
- package/docs/cli-reference.md +599 -0
- package/docs/command-list.md +51 -0
- package/docs/compose-patterns.md +99 -0
- package/docs/concepts.md +171 -0
- package/docs/configuration-essentials.md +172 -0
- package/docs/configuration-reference.md +621 -0
- package/docs/environment.md +760 -0
- package/docs/extending.md +43 -0
- package/docs/faq.md +111 -0
- package/docs/getting-started.md +608 -0
- package/docs/harness-surfaces.md +433 -0
- package/docs/joining-a-team.md +76 -0
- package/docs/release-policy.md +49 -0
- package/docs/safety-and-autonomy.md +419 -0
- package/docs/troubleshooting.md +361 -0
- package/docs/tutorial.md +170 -0
- package/docs/work-and-browser.md +254 -0
- package/libexec/browser-operation.cjs +186 -0
- package/libexec/fence-marker.cjs +101 -0
- package/libexec/fence-marker.d.cts +24 -0
- package/libexec/fenced-group-runner.cjs +77 -0
- package/libexec/fenced-supervisor.cjs +137 -0
- package/libexec/generated-filesystem.cjs +731 -0
- package/libexec/install-filesystem.cjs +225 -0
- package/libexec/rulesync-generator.NOTICE.md +1112 -0
- package/libexec/rulesync-generator.cjs +743 -0
- package/libexec/surface-generator-worker.cjs +266 -0
- package/libexec/surface-output-reader.cjs +99 -0
- package/libexec/surface-scratch-cleanup.cjs +14 -0
- package/libexec/validate-harness-evidence.d.mts +183 -0
- package/libexec/validate-harness-evidence.mjs +1312 -0
- package/package.json +74 -4
- package/surfaces/README.md +33 -0
- package/surfaces/agents/evaluator.agent.md +76 -0
- package/surfaces/guards/bash-guard.sh +48 -0
- package/surfaces/guards/claude.adapter.json +25 -0
- package/surfaces/guards/codex.adapter.json +24 -0
- package/surfaces/guards/opencode.adapter.json +25 -0
- package/surfaces/references/browser.md +63 -0
- package/surfaces/references/test-data-and-personas.md +84 -0
- package/surfaces/references/testing-tiers.md +11 -0
- package/surfaces/skills/cockpit-browser.skill.md +54 -0
- package/surfaces/skills/cockpit-explain.skill.md +32 -0
- package/surfaces/skills/cockpit-fix.skill.md +37 -0
- package/surfaces/skills/cockpit-setup.skill.md +39 -0
- package/surfaces/skills/cockpit-work.skill.md +34 -0
- package/surfaces/skills/collection.json +5 -0
- package/surfaces/skills/procedures/explain.md +61 -0
- package/surfaces/skills/procedures/fix.md +81 -0
- package/surfaces/skills/procedures/setup.md +379 -0
- 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.
|