diff --git a/docs/claude/cowork.md b/docs/claude/cowork.md index 9e36ed3fa..69033784c 100644 --- a/docs/claude/cowork.md +++ b/docs/claude/cowork.md @@ -8,7 +8,7 @@ Cowork is not an implemented session mode: no Cowork session can be created or r `cowork/output-integration` now holds the whole native source stack, and none of it runs: the activation seam (`cowork/native-activation.ts`, `COWORK_NATIVE_ENVIRONMENT_ACTIVATED = false`) answers `undefined`, the host-env graph loads lazily behind it (`test/cowork/host-env-lazy.test.ts`), and no VM, Hypervisor.framework call or app launch has ever been made from it. Wire contract and revision history: [cowork-native-worker.md](../cowork-native-worker.md) (revision 3 added host-backed shares, cold resume and the guest file channel). There is no NIC and no vsock anywhere in it. -- **libkrun stack (SH2).** `apple/Cowork/WinterCoworkLibkrun` is a pinned patch queue (0004-0026) over upstream libkrun v1.19.6 with a reproducible build of one stripped archive that the worker links. Patches 0024-0026 are SH2: the confined virtio-fs server core, its git rules and quarantine, and the guarded fs device with the shares ABI gate. Nothing in the repository imports the directory (a test pins that); its README holds the pins and the rebuild steps. A release ships the worker only with the archive inputs ([release.md](./release.md#the-cowork-native-pair-is-an-explicit-choice)). +- **libkrun stack (SH2).** The libkrun patch-queue package under `apple/Cowork/` (not named by path outside CI: its anti-wiring guard refuses any other referrer) is a pinned patch queue (0004-0026) over upstream libkrun v1.19.6 with a reproducible build of one stripped archive that the worker links. Patches 0024-0026 are SH2: the confined virtio-fs server core, its git rules and quarantine, and the guarded fs device with the shares ABI gate. Nothing in the repository imports the directory (a test pins that); its README holds the pins and the rebuild steps. A release ships the worker only with the archive inputs ([release.md](./release.md#the-cowork-native-pair-is-an-explicit-choice)). - **Host-backed shares over virtio-fs (SH6, guest side).** PID 1 (`apple/Cowork/WinterCoworkGuest/init/shares.c`) reads the virtio-fs tag inventory (it must equal the declared tags), mounts each share with `nosuid,nodev` and `dax=never` on a checked mount point's descriptor, then verifies every mount in `/proc/self/mountinfo`; any failure unmounts what it mounted. Three Winter shares are fixed: guidance at `/run/winter/shared-instructions` (read-only; PID 1 also links `/workspace/.winter/WINTER.md` to it), memory at `/workspace/.winter/memory` and outputs at `/workspace/outputs`, all `noexec`. A connected Mac folder is a guest share at `/workspace/folders/` (mode 0700 mount point, `exec` kept because builds run there, read-only when the share is). Guest ownership and modes on a share are no boundary: the host serves shares under simplified ownership. - **Plan view.** For a conversation under policy `plan`, PID 1 makes `/workspace/plan//` (contract 12.5) for its own conversation only: owned by the conversation's tool uid alone (0700, never the workspace group), parents never symlinks, refused when a later epoch already exists. The guest supervisor admits it writable only under `plan` and never below an epoch already made; the tool launcher mounts it writable for the file worker only. - **Environment image `/etc/gitconfig`.** The image carries a fixed system gitconfig (`scripts/cowork-guest-artifact/environment/gitconfig`, hash pinned in `pins.json`): an empty git template directory, `core.hooksPath=/dev/null`, no fsmonitor, no credential helper, no include, `protocol.ext.allow=never`. The tool launcher mounts it read-only at `/etc/gitconfig` for the process worker; `verify.py` accepts exactly those settings and refuses a stray `/etc/gitconfig`. diff --git a/docs/claude/release.md b/docs/claude/release.md index b73b98189..0ec662f19 100644 --- a/docs/claude/release.md +++ b/docs/claude/release.md @@ -24,7 +24,7 @@ bun run scripts/release.ts # real release (bumps first; -- | `COWORK_LIBKRUN_INCLUDE` (the directory holding `libkrun.h`) AND `COWORK_LIBKRUN_ARCHIVE` (the stripped production archive) | build | `buildCoworkNative` builds the launcher (`swift build`) and the worker (`apple/Cowork/WinterCoworkHVFWorker/build.py`, which refuses unless the header and archive hash to that folder's `pins.json`) into `dist/cowork-native`; project.yml's "Embed Cowork native" phase (`scripts/embed-cowork-native.sh`) signs them into `Winter.app/Contents/Helpers/WinterCowork/` and writes `Contents/Resources/cowork-native-pins.json`. The release then verifies identifiers, team, hardened runtime, the stated designated requirement, entitlements (worker: the hypervisor key alone; launcher: none), platform dylibs only, no test hooks, and that the pin manifest's CDHashes and libkrun/worker/guest-artifact pins are the ones in this checkout. | | `COWORK_NATIVE=omit` (and neither libkrun variable) | omit | Nothing is built or embedded: no `WinterCowork` helpers, no pins file. The release fails if a leftover from an earlier build is in the bundle (`checkCoworkNativeOmitted`). | -Anything else exits before any build with a message naming both ways out: neither given; only one of the two libkrun variables; `COWORK_NATIVE=omit` together with either libkrun variable; or any other value of `COWORK_NATIVE`. `omit` is never the default. `release.ts` does not build or fetch the libkrun archive; the patch queue and its reproducible build are in `apple/Cowork/WinterCoworkLibkrun` (`scripts/build_archive.py`), and its stripped archive is what `COWORK_LIBKRUN_ARCHIVE` points at. A release that must not wait on one uses `COWORK_NATIVE=omit`. `scripts/build-cowork-native.ts` reads the same two variables (or `--libkrun-include` / `--libkrun-archive`; `--launcher-only` skips the worker), and `embed-cowork-native.sh` itself also honours `COWORK_NATIVE=omit` and rejects any other value. +Anything else exits before any build with a message naming both ways out: neither given; only one of the two libkrun variables; `COWORK_NATIVE=omit` together with either libkrun variable; or any other value of `COWORK_NATIVE`. `omit` is never the default. `release.ts` does not build or fetch the libkrun archive; the patch queue and its reproducible build are in the libkrun patch-queue package under `apple/Cowork/` (its `scripts/build_archive.py`; deliberately not named by path outside CI, which its anti-wiring guard enforces), and its stripped archive is what `COWORK_LIBKRUN_ARCHIVE` points at. A release that must not wait on one uses `COWORK_NATIVE=omit`. `scripts/build-cowork-native.ts` reads the same two variables (or `--libkrun-include` / `--libkrun-archive`; `--launcher-only` skips the worker), and `embed-cowork-native.sh` itself also honours `COWORK_NATIVE=omit` and rejects any other value. ## Rolling back across a schema bump A release that raises `RUNTIME_STATE_SCHEMA_VERSION` (the Cowork tables arrived in v8 to v17; v18 added the session binding, v19 the session reservations, v20 the export content binding, v21 the stable guest uids and cold-resume records; it is v21 now) cannot be undone by installing the older app: the older build refuses the newer store (`newer-schema`). A revert release reverts the feature, never the schema. The user-facing way back is `winter migrate --cowork-schema --rollback` with the newer CLI and the daemon stopped, before installing the older app (it accepts v8..v21, drops only empty Cowork tables and refuses with `cowork-data-present` if one holds a row); a store left at v18, v19 or v20 by an intermediate build needs the same step. Put that line in the release notes of any release that bumps the schema (see `docs/RELEASE-NOTES-cowork-schema.md`; what each version adds: [settings-and-migrations.md](./settings-and-migrations.md#runtime-state-schema-v21-and-the-way-back)). diff --git a/docs/cowork-status.md b/docs/cowork-status.md index 4a8c2db38..fb0b85122 100644 --- a/docs/cowork-status.md +++ b/docs/cowork-status.md @@ -27,7 +27,7 @@ The 2026-10-12 text above (except the opening paragraph, which is re-dated and e Everything below is source on the integration branch; none of it runs, and nothing has booted. - **Still true: no Cowork session can be created.** `session.create {mode: "cowork"}` still answers `unsupported_topology` for every role. The session door's records exist (runtime-state schema v18 to v21: binding location, reservations, export content binding, stable guest uids and cold-resume records; see [settings-and-migrations.md](claude/settings-and-migrations.md#runtime-state-schema-v21-and-the-way-back)) but no door is switched on, and the native activation seam (`cowork/native-activation.ts`) answers `undefined`. -- **Native source now exists end to end, unwired.** The Swift launcher (`apple/Cowork/WinterCoworkLauncher`), the C VM worker (`apple/Cowork/WinterCoworkHVFWorker`), the host adapter and wire contract (`packages/core/src/cowork/native/`, [cowork-native-worker.md](cowork-native-worker.md), revision 3), the guest PID 1, relay and file channel (`apple/Cowork/WinterCoworkGuest`) and a pinned libkrun patch queue (`apple/Cowork/WinterCoworkLibkrun`, patches 0004-0026 over libkrun v1.19.6). The release script requires an explicit choice: `COWORK_NATIVE=omit` or both libkrun inputs ([release.md](claude/release.md#the-cowork-native-pair-is-an-explicit-choice)). +- **Native source now exists end to end, unwired.** The Swift launcher (`apple/Cowork/WinterCoworkLauncher`), the C VM worker (`apple/Cowork/WinterCoworkHVFWorker`), the host adapter and wire contract (`packages/core/src/cowork/native/`, [cowork-native-worker.md](cowork-native-worker.md), revision 3), the guest PID 1, relay and file channel (`apple/Cowork/WinterCoworkGuest`) and a pinned libkrun patch queue (the libkrun patch-queue package under `apple/Cowork/`, patches 0004-0026 over libkrun v1.19.6). The release script requires an explicit choice: `COWORK_NATIVE=omit` or both libkrun inputs ([release.md](claude/release.md#the-cowork-native-pair-is-an-explicit-choice)). - **libkrun SH2:** the confined virtio-fs server core (0024), its git rules and quarantine (0025), and the guarded fs device with the shares ABI gate (0026). - **Guest side of host-backed shares (SH6)** and the **plan view** `/workspace/plan//` are in the guest init; Mac folders are guest shares at `/workspace/folders/` over virtio-fs; the memory share is at `/workspace/.winter/memory`; the image carries a fixed `/etc/gitconfig` for the process worker. Details: [cowork.md](claude/cowork.md#native-guest-stack-on-the-integration-branch-source-only-never-booted). - **Cold resume:** the host half (store state, continuation, proven-ended boots) and the guest owner patch are both present; the host port is not supplied by any production composition, so a recorded-backend conversation still refuses `cold_resume_unavailable`.