Open Cut is a pnpm application workspace built on a product-independent Go cold-start, release, and sidecar-control substrate.
The installed bootstrap surface contains the platform host, launcher, and a
stable product-CLI resolver. A launcher-managed release is one atomic
launcher + payload bundle; the opaque payload contains the app runtime and the
versioned product CLI at payload/bin/open-cut[.exe].
Start with AGENTS.md.
Install the Go version declared by go.mod and a Node version satisfying the
root package.json first. The repository does not install either runtime.
go install ./cmd/oc-control
oc-control bootstrap
oc-control doctor
oc-control protocol check
oc-control clean --scope quick
oc-control dev startoc-control bootstrap validates the installed Node and pnpm versions, performs
a frozen workspace install, and enables the repository pre-commit hook. It never
installs or replaces development tools. After control source changes, rerun
go install ./cmd/oc-control.
By default the dev suite owns
<repo>/.tmp/oc-control/dev/dev/default; the final two segments are the cell's
channel and namespace. --base-dir may select another clean absolute path with
the same suffix. That final path travels unchanged into each member's launch
envelope, each sidecar derives its app directory, and the API stores SQLite at
<base-dir>/api/database/open-cut.db.
The current executable acceptance paths are:
oc-control harness broker
oc-control harness sidecars
oc-control harness cold-start
oc-control pack mac --arch arm64 --version 0.1.0-beta.1
oc-control verify mac --arch arm64 --bundle dist/releases/0.1.0-beta.1/mac-arm64/open-cut-0.1.0-beta.1-mac-arm64.release-bundle.tar.zstbrokerexercises the real cell lock, TCP rendezvous, capabilities, WebSocket, endpoint publication, READY, and authenticated status.sidecarsbuilds and executes the unique web/API sidecar entries against the Go broker, verifies that API migrations and SQLite initialization finish before READY, then verifies shared shutdown and clean process exit.cold-startbuilds real B0/L1 and fixture payload binaries, performs genesis confirmation, rotates the trust root, executes a broker-mediated v1→v2 steady-state handoff, proves offline last-good boot, and proves pre-READY rollback.dev startbuilds the workspace, then conducts the cell as a suite of detached, argv-stamped member processes and exits once READY is confirmed: one control member (anoc-controlinternal mode hosting the cell broker and development signer) plus the Electron, web, and API peer sidecars. No process supervises the suite;dev statusreports recorded-versus-live truth fail-closed,dev stopterminates only stamp-verified members,dev restartadvances the generation, anddev logssnapshots per-member per-generation files. Electron discovers the web endpoint through the shared TCP broker and never owns the other processes. Its renderer always loadsoc://app/; an Electron protocol adapter proxies that stable origin to the current loopback Web lease. Web runs React through Vite in dev and serves the Vite production build through the same thin sidecar wrapper in a release. Its stable/apiingress continuously follows the native Go API sidecar lease.- Sidecar state is continuously reconciled over TCP. Revisioned WebSocket snapshots provide low-latency changes, status polling repairs gaps, and the runner restarts unexpectedly exited peers without changing ownership boundaries.
- The sidecar wire contract is authored only in
protocol/sidecar/v1/main.tsp.oc-control protocol generateproduces OpenAPI, JSON Schema, and the Go/TypeScript bindings and decoders inpackages/sidecar-protocol; transport and reconciliation stay inpackages/sidecar-client.oc-control protocol checkrejects generated drift. packdiscovers every app sidecar from its language-neutral manifest, deploys their production trees, generates a platform-resolved generic runtime topology, builds the Electron full pack andcmd/cli, and archives them with the versioned launcher.full-packextracts that real archive and invokes the versioned L1 launcher, proving that the same runner starts independent Electron/web/API peers, aggregates READY, publishes endpoints, broadcasts lifecycle control, and exits the runtime tree cleanly without a GUI.
Keep exploratory UI work out of the default dev data by giving the cell an
isolated base directory. The path must end in the canonical dev/default cell
suffix, and every companion command must use the same value:
oc-control dev start --base-dir .tmp/oc-control/ui-audit/dev/default
oc-control dev status --base-dir .tmp/oc-control/ui-audit/dev/default
oc-control dev logs --base-dir .tmp/oc-control/ui-audit/dev/default --app api
oc-control dev restart --base-dir .tmp/oc-control/ui-audit/dev/default
oc-control dev stop --base-dir .tmp/oc-control/ui-audit/dev/defaultstart returns once READY is confirmed and leaves only the detached suite
running; every command above is bounded. Inspect the live Electron renderer
without discovering its transient CDP port by hand:
oc-control dev inspect --base-dir .tmp/oc-control/ui-audit/dev/default \
--screenshot .tmp/ui-audit.png
oc-control dev inspect --base-dir .tmp/oc-control/ui-audit/dev/default \
--snapshot --match Viewer
oc-control dev inspect --base-dir .tmp/oc-control/ui-audit/dev/default \
--action click --role tab --name Streams --watch-errors 250ms \
--snapshot --match Source
oc-control dev inspect --base-dir .tmp/oc-control/ui-audit/dev/default \
--eval 'document.body?.innerText'
oc-control dev inspect --base-dir .tmp/oc-control/ui-audit/dev/default \
--eval-file .task/resources/ui-matrix.js --watch-errors 1s
oc-control dev inspect --base-dir .tmp/oc-control/ui-audit/dev/default \
--set-file .tmp/fixture.webm--snapshot reads the browser accessibility tree plus generic renderer
geometry, focus, overflow, scroll, clipping, and disabled-control state without
starting a second browser. Its node sets are bounded; --match applies a
case-insensitive role/name filter while retaining the full-page summary. Combine
snapshot, eval, and screenshot flags when one settled renderer state should
produce all three forms of evidence.
--eval-file runs the same awaited, return-by-value evaluation as --eval but
reads it from a non-empty regular file inside the repository. It is mutually
exclusive with inline --eval, rejects files larger than 256 KiB, and reports
the resolved file path and byte size. This keeps repeatable multi-state audits
in .task/resources/ without shell quoting or a second browser.
--action click resolves one exact accessible role/name pair, rejects missing,
ambiguous, ignored, disabled, or layout-less targets, dispatches viewport CDP
mouse input, and waits for two animation frames before later snapshot or
screenshot flags run. The receipt records the resolved target bounds and click
point without exposing a reusable stale node reference.
--watch-errors opens a bounded 50 ms–30 s observation window around the other
inspect operations and reports renderer exceptions, console errors/assertions,
and Chromium log errors. Enabling the CDP domains may replay retained console
entries, so inspect drains that startup history before opening the window.
Collection stays on the existing inspect connection, retains at most 512 raw
events and 100 normalized errors, and installs no persistent page observer.
--set-file accepts only a non-empty regular file, reports the exact attached
byte size, and targets the first enabled file input. It is a generic renderer
actuator; it does not import media through an internal API or learn product
semantics.
When a reproducible local media fixture is needed, record the running renderer through the contained media toolchain. On macOS, optional narration gives the transcription path known words without adding a checked-in binary fixture:
oc-control dev record --base-dir .tmp/oc-control/ui-audit/dev/default \
--output .tmp/ui-audit.webm --duration 8 \
--speech 'A clear local workflow keeps creative work moving.'Use oc-control dev stop to end the suite. oc-control clean --scope quick
removes stopped ad-hoc dev and harness data while preserving the expensive
media-toolchain cache; it refuses directories belonging to a live cell.
Every public target is named <platform>-<arch>, using only mac|win|linux and
arm64|x64. Go/Electron internal names such as darwin and amd64 do not appear
in release paths or artifact names.
The macOS Day 0 loop is:
version=0.1.0-beta.1
target=mac-arm64
bundle=".tmp/delivery/open-cut-${version}-${target}.release-bundle.tar.zst"
oc-control release keygen --output .tmp/delivery/key.json --id local
oc-control pack mac --arch arm64 --version "$version" --output "$bundle"
oc-control release create --bundle "$bundle" --origin .tmp/delivery/origin --key .tmp/delivery/key.json
oc-control verify mac --arch arm64 --origin .tmp/delivery/origin --channel beta --key .tmp/delivery/key.json
oc-control serve --root .tmp/delivery/origin --listen 127.0.0.1:41000With that origin running, a separate terminal can simulate final-user actions:
workspace=.tmp/delivery/install-case
receipt="$workspace/receipts/install-receipt.json"
oc-control harness install mac --arch arm64 --workspace "$workspace" \
--origin .tmp/delivery/origin --origin-url http://127.0.0.1:41000 \
--key .tmp/delivery/key.json --headless
oc-control inspect --receipt "$receipt"
"$(jq -r .cliPath "$receipt")" status --receipt "$receipt"
oc-control harness run --workspace "$workspace" --receipt "$receipt" --headless
oc-control harness uninstall --workspace "$workspace" --receipt "$receipt" --purgeThe receipt lives outside the installed application so uninstall is repeatable.
harness run executes the installed platform host, not a source-tree shortcut.
The installed CLI resolver reads runtime.json.active, dispatches to the fixed
CLI path in that version, and uses the broker's observe-only token only for
control-plane discovery. A non-help business command asks the installed
lifecycle host to ensure readiness, then the versioned CLI reaches the product
API with a separate absorbed business grant; it never joins runtime topology or
inherits lifecycle authority from the API.
The public CI builds and verifies native mac-arm64, win-x64, and linux-x64
full packs; macOS additionally runs the install/offline-relaunch/uninstall loop.
Use a structured timing report when comparing delivery changes instead of inferring performance from the duration of one compound shell step:
oc-control pack mac --arch arm64 --version 0.1.0-beta.1 \
--output "$bundle" \
--timing-report .tmp/oc-control/timing/mac-arm64/pack.json
oc-control timing summary \
--report .tmp/oc-control/timing/mac-arm64/media-toolchain.json \
--report .tmp/oc-control/timing/mac-arm64/whisper-toolchain.json \
--report .tmp/oc-control/timing/mac-arm64/pack.json
oc-control timing compare \
--baseline .tmp/timing-baseline/pack.json \
--candidate .tmp/oc-control/timing/mac-arm64/pack.jsonThe API sidecar build automatically writes media and transcription reports
under .tmp/oc-control/timing/<target>/. Harness commands write both their
normal report and reports/timing.json below the selected workspace. Reports
are written on failure as well as success and record reuse decisions separately
from phase duration.
Each native CI lane publishes these JSON reports in a separate lightweight
open-cut-timing-<target> artifact and renders them in the job summary. Its
cache report distinguishes an exact key hit, a
restore-prefix fallback, a miss, and not-needed when an exact published
closure makes colder inputs irrelevant. The workflow restores the published
closure first; only a fallback or miss restores source archives and the C tree
and installs native compiler prerequisites. This keeps a normal product/UI
change from downloading multi-gigabyte build material that pack will never
inspect. The media reports independently show
whether the restored closure and compiled C tree were actually reused. Compare
the same target and cache cohort before attributing a duration change to code.
An app artifact check that opts into generic timing also emits
artifact-check-<app>-<index>.json; the app owns its phases while the packager
only provides the output path and rejects a missing or invalid declared report.
Media builds also carry content-addressed qualification receipts beside their
manifests. A receipt can suppress only the expensive owner-defined replay it
names: deployed bytes, release baselines, base/renderer conformance, and a
Whisper process smoke are still checked. A missing, malformed, or mismatched
receipt causes a real qualification replay and atomic receipt replacement.
The media, Whisper, and app artifact-check reports expose this as
renderer-relink-qualification / whisper-qualification decisions with
reused, replayed, or producer-side produced values.
The CI C-tree cache is a sequence of validated producer generations below one
exact build-identity prefix. A restored generation is only a reuse hint:
EnsureTree still checks the embedded compiler/build-logic stamp and every
required output. CI consults it only after the published closure fails exact
reuse, and saves a new generation only when the media timing report states
c-build-tree=rebuilt; a published-closure fast path records not-inspected
and can never download or promote an unchecked fallback tree. Read either
decision without parsing report JSON by hand:
oc-control timing decision \
--report .tmp/oc-control/timing/mac-arm64/media-toolchain.json \
--name c-build-treePull-request caches are visible to later commits in the same pull request but
are not promoted to main. This removes repeated qualification work while a PR
is being repaired; the first post-merge run still verifies and publishes the
corresponding main-scoped artifacts.
Generated workspace cleanup is deliberately repository-scoped:
oc-control clean --scope quick # per-entry .tmp cleanup; keeps media-toolchain caches
oc-control clean --scope temp # .tmp only
oc-control clean --scope build # apps/*/dist and packages/*/dist
oc-control clean --scope all # both generated surfaces
oc-control clean --scope all --dry-runEvery report item carries its measured byte size, so --dry-run doubles as a
disk usage probe over the generated surfaces. quick removes harness
workspaces, ad-hoc debug directories, and the dev cell, but keeps the
media-toolchain download cache whose loss forces a full native recompile.
Directories holding a held broker.lock belong to a running cell and are
reported in-use instead of being removed, in every scope.
The command never accepts arbitrary deletion targets and never removes dependency trees. Use it instead of shell-recursive deletion during normal development.
Run repository checks with:
go test ./...
pnpm build
pnpm format
pnpm lint
pnpm test
oc-control protocol check
oc-control harness guardTop-level tests in apps/api/tests declare their scheduling contract as the
first statement: parallelAPITest(t) for tests that own all mutable resources,
or serialAPITest(t, reason) for a documented shared/process-wide constraint.
The package's suite-topology test rejects missing or implicit declarations.
This keeps the race lane parallel by default without allowing a new test to
silently serialize the package or share a resource accidentally.