Skip to content

Repository files navigation

open-cut

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.

Day 0 development path

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 start

oc-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.zst
  • broker exercises the real cell lock, TCP rendezvous, capabilities, WebSocket, endpoint publication, READY, and authenticated status.
  • sidecars builds 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-start builds 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 start builds the workspace, then conducts the cell as a suite of detached, argv-stamped member processes and exits once READY is confirmed: one control member (an oc-control internal mode hosting the cell broker and development signer) plus the Electron, web, and API peer sidecars. No process supervises the suite; dev status reports recorded-versus-live truth fail-closed, dev stop terminates only stamp-verified members, dev restart advances the generation, and dev logs snapshots per-member per-generation files. Electron discovers the web endpoint through the shared TCP broker and never owns the other processes. Its renderer always loads oc://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 /api ingress 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 generate produces OpenAPI, JSON Schema, and the Go/TypeScript bindings and decoders in packages/sidecar-protocol; transport and reconciliation stay in packages/sidecar-client. oc-control protocol check rejects generated drift.
  • pack discovers every app sidecar from its language-neutral manifest, deploys their production trees, generates a platform-resolved generic runtime topology, builds the Electron full pack and cmd/cli, and archives them with the versioned launcher.
  • full-pack extracts 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.

UI development loop

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/default

start 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.

Local delivery loop

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:41000

With 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" --purge

The 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.

Delivery timing reports

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.json

The 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-tree

Pull-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-run

Every 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 guard

Top-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.

About

Product-independent launcher, release, and sidecar substrate for Open Cut

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages