BLUEPRINT

Remote handoff · Revised path · Proof gated

A remote agent can ship Weaver capture without refactoring the runtime first

Weaver's normal bootstrap already loads the manifest, storage, providers, images, QuickJS, and WidgetApp before it enters the Native SDK runner. The runner already has a headless sibling in session replay, so capture belongs there. Do not extract WidgetSession and do not add a second executable until a receipt proves either is needed. The corrected GPU frame sequence is still unverified: all three local prototype PNGs were fully opaque black, so the remote implementation starts by producing one visibly correct image.

The handoff decision

HIGHtechnical feasibility
0 / 3prototype PNGs with content
1shipping binary until measured
3 / 5current proof level

Recommended decision: add capture beside runSessionReplay, reuse the existing Weaver bootstrap and automation command model, and ship one-shot capture before action scripts or a viewer. A persistent agent session stays deferred until valid captures establish real startup and interaction latency.

QuestionDecisionReason
Extract WidgetSession firstNoThe current bootstrap reaches the runner with the real bundle and app already constructed.
Add weaver-capture as another executableDeferSession replay already lives in the production binary behind an environment branch. Measure binary and resident cost before splitting it.
First agent contractOne-shot captureA fresh process removes cross-rebuild node identity and lifetime problems.
Interaction modelReuse current commandsThe SDK already dispatches click, drag, wheel, key, text, context menu, resize, snapshot, and screenshot actions.
Recorded external inputsReuse session journalsJournals already carry events, effect results, fingerprints, screenshot marks, and mismatch ordinals.
New fixture formatWeaver providers onlyCPU, memory, media, and audio provider frames cross Weaver's host pipe and are not journaled by the SDK.
Persistent agent sessionMeasure laterThe only timing receipts came from invalid black captures.

Source: Weaver runtime/src/main.zig:1239-1491; Native SDK src/app_runner/root.zig:392-417,693-878; local review and prototype inspection on 2026-08-24.

The safety fact is now narrower and better: capture can branch at the existing SDK runner after Weaver has built the real app. Source inspection and the reproduced null-backend link failure take that fact to proof level 3. A valid end-to-end PNG is the missing level 4 proof.

Start from a clean remote checkout

The uncommitted runHeadlessCapture prototype exists only in a separate local checkout. It is evidence, not an input. A remote agent must reimplement the small runner change from the contracts below and must not assume the prototype was pushed.

ItemKnown evidence stateRemote rule
Weaver sourcee69a0997c5a883a69514674fab7dfcdbe0016114Record the assigned checkout's actual SHA before editing. Do not silently reset a newer branch to this evidence commit.
Native SDK pin4c5c0999c2324b8dc2016625e85571e554b2484aInitialize the submodule, create a real branch inside it, and push its commit before updating Weaver's pointer.
PrototypeUncommitted local submodule diffDo not depend on it. The shipping change must factor shared startup instead of copying its event sequence.
Prototype outputClock, text, and pomodoro PNGs were uniform blackDimensions, PNG validity, byte count, and nonzero alpha do not prove a capture.
ToolchainZig 0.16.0; Node 24.19.0 locallyZig must be 0.16.0. Node must satisfy the repository's >=20.11 engine.

Source: repository commits and manifests, package.json, .gitmodules, local Git state, and Native SDK AGENTS.md.

# Fresh remote setup
git clone --recurse-submodules https://github.com/SunkenInTime/weaver.git
cd weaver
git submodule update --init --recursive
npm ci

# Record provenance before work starts
git rev-parse HEAD
git -C runtime/native-sdk rev-parse HEAD
node --version
zig version

# Create branches in both repositories before the first edit
git switch -c agent/widget-capture
git -C runtime/native-sdk switch -c agent/headless-capture

Source: repository remotes and the submodule branch declaration in .gitmodules. Branch names are examples; keep the remote executor's assigned naming convention.

host requirement Use a macOS remote for the first complete reference-capture proof. A Windows remote owns the Windows proof. A Linux-only machine can edit and run portable SDK tests, but the current Weaver runtime build accepts macOS and Windows targets only, so Linux cannot claim end-to-end completion.

Use the runner path that already exists

Source: Weaver bootstrap in runtime/src/main.zig:1239-1491; SDK runner, session replay, automation server, session journal, and screenshot renderer at Native SDK 4c5c0999.

The runner branch is the only new lifecycle. The CLI remains responsible for checking and bundling. Weaver remains responsible for its actual app. The SDK remains responsible for platform events, retained rendering, screenshots, snapshots, and input dispatch.

Build five proof-gated work packages

Package 0: fix and pin the backend gate

  • Reproduce zig build -Dplatform=null -Dautomation=true -Doptimize=ReleaseFast failing on _native_sdk_appkit_render_host_run.
  • Gate --render-host on the selected Native SDK backend, not only builtin.os.tag. If main.zig cannot read that backend today, expose it through weaver_build_options or move the render-host branch into backend-specific code.
  • Add a macOS null-backend build test so the link regression cannot return.
  • After the fix, run the unmodified clock bundle. Reaching UnsupportedViewKind proves the real Weaver bootstrap entered the null runner.

Exit: the null build links, the normal macOS build still accepts --render-host, and the capture environment never enters render-host mode.

Package 1: land a real Native SDK capture mode

  • Add the capture branch beside runSessionReplay in src/app_runner/root.zig.
  • Factor the null startup dispatch shared by normal null execution and capture. Do not keep two handwritten copies of app start, appearance, surface, window, and shutdown ordering.
  • Enable gpu_surfaces and image_decode for capture. Install macOS headless text services only in the macOS-backend build.
  • Drive the created GPU view with gpu_surface_resized and the frame events the runtime actually requests. Do not preserve the prototype's unexplained two-frame constant.
  • Render through renderCanvasScreenshot, encode PNG, and reuse the existing automation snapshot generator.
  • Count pixels that differ from the declared clear color. Also report retained node, command, image, and font counts. Alpha alone is not a content test.

Exit: clock, styling-text, styling-images, and pomodoro produce the expected dimensions and visibly non-flat content. Styling-interaction exposes actionable semantics. Noro Shell proves registered fonts and local images. The agent or human must open the PNGs before calling this package done.

Package 2: expose weaver capture

  • Add weaver capture <directory> --out <file.png> to the closed CLI parser.
  • Call bundleWidget directly. Never call devWidget, register the widget, start weaverd, open a desktop window, or connect shared renderer IPC.
  • Spawn the existing widget runtime with an internal capture request. Keep stdout to one JSON receipt and send human diagnostics to stderr.
  • Create an explicit capture-state root that works on macOS and Windows. The runtime must not read or write the live widget store, logs, placement, or provider endpoint by accident.
  • Write PNG, snapshot, and receipt files atomically. A failed command must not leave an artifact that looks complete.

Exit: a fresh agent can run one command from a source widget directory and receive the PNG, semantic snapshot, receipt, and an exit status that agrees with them.

Package 3: add short deterministic action scripts

  • Accept repeatable actions or an action file in the same short-lived process that produces the final capture.
  • Resolve targets by role, accessible name, and current semantic state. An ambiguous target must list the matching controls instead of choosing one.
  • Translate resolved actions into the existing automation command model and dispatcher. Do not create another click, drag, wheel, key, text, or resize implementation.
  • Allow explicit clock advancement. Never sleep until an animation looks settled.
  • Accept a session journal as an optional recorded-input mode. Keep explicit Weaver provider fixtures for provider states that the SDK journal does not carry.

Exit: an action script starts the pomodoro, advances its clock, and captures the changed state; a slider drag changes both the snapshot and the PNG; the same script can be attached to a bug report and replayed in CI.

Package 4: decide the viewer from receipts

  • Measure the valid one-shot path across the example corpus before choosing a persistent agent process.
  • If process startup dominates useful work, keep a session alive internally. If it does not, keep the agent contract one-shot and reserve persistence for the human viewer.
  • Build the loopback viewer as a PNG and semantic-overlay client. It must never reproduce widget layout in HTML.
  • Add repository pixel gates for selected examples. Keep weaver check focused on failures knowable without an expensive render until capture latency earns a broader default.

Exit: the viewer architecture cites the measured bundle, spawn, startup, render, encode, and write costs. No hidden frame cadence ships.

Make the receipt sufficient without the source

# Contract shape; fields marked number carry measured integer counts or durations
type CaptureReceipt = {
  schema: "weaver.capture.v1";
  status: "ok" | "error";
  provenance: {
    weaverCommit: string;
    nativeSdkCommit: string;
    bundleSha256: string;
    platform: string;
  };
  output: {
    image: string;
    snapshot: string;
    widthPx: number;
    heightPx: number;
    scale: number;
    pngBytes: number;
  };
  renderer: {
    pixels: "reference";
    textMeasurement: "estimator" | "coretext";
    eventsDriven: string[];
    framesDriven: number;
    retainedRevision: number;
    commands: number;
    nodes: number;
    pixelsDifferentFromClear: number;
  };
  pending: {
    timers: number;
    fetches: number;
    images: number;
    providers: string[];
    frameRequests: number;
  };
  timingUs: {
    bundle: number;
    spawn: number;
    startup: number;
    render: number;
    encode: number;
    write: number;
    total: number;
  };
  inputs: {
    clock: string;
    storage: string;
    providerFixtureSha256?: string;
    sessionJournalSha256?: string;
  };
  warnings: string[];
  error?: { name: string; ask: string; remedy: string };
};

Source: Weaver's agent-facing error rule, the existing automation snapshot, session journal provenance, and the black-frame failure found by the prototype.

A blank image is not automatically an error because a widget may intentionally be transparent. The receipt makes blankness explainable: clear-color difference, retained commands, semantic nodes, and pending work tell an agent whether it captured an intentional empty state, an undriven frame, or unfinished input.

Measure before setting a latency or frame budget

CaseWhat it provesRequired artifact
examples/clockKnown 240 px by 110 px static baselinePNG, snapshot, full timing receipt
examples/styling-textText measurement, wrapping, and glyph resourcesReference PNG on every host; macOS parity PNG when available
examples/styling-imagesLocal decode, registration, and drawPNG plus image pending and failure counts
examples/styling-interactionSemantic targeting and real input dispatchBefore and after snapshots and PNGs
examples/pomodoroExplicit clock advancementAction script and changed-state receipt
examples/noro-shellHeavier bundle, registered font, and several imagesCold and warm stage timings
Provider-backed exampleNamed missing input and fixture behaviorError receipt without fixture; valid capture with fixture

Source: shipped Weaver examples and the project's rule that every limit needs a receipt.

Record cold and warm runs separately. Keep bundling separate from process startup and screenshot work. Only after this table is complete may the implementation set a latency tripwire, a maximum driven-frame count, or a policy for keeping an agent process alive.

Say which platform truth each image carries

ModeWhat it usesWhat it may claimGate
macOS referenceNull backend, estimator text, CPU reference pixelsDeterministic agent feedback without a window or Metal presentationMust build and run without the Metal toolchain
macOS paritymacOS backend, CoreText measurement, CPU reference pixelsDesktop-equivalent layout measurement, not OS glyph rasterization or compositor parityRequires a macOS build and currently encounters the Metal toolchain dependency
Windows referenceNull backend and engine measurementOnly what an actual Windows capture provesCompare against a live Windows widget before naming parity
Linux portable workNative SDK portable testsSDK behavior onlyCannot close the Weaver end-to-end gate

Source: Native SDK macOS installHeadlessTextServices, Windows platform services, screenshot renderer, and Weaver runtime/build.zig target checks.

There is no proven Windows capture mismatch yet. The absence of a Windows headless text hook is a question, not a receipt. The remote owner must compare current Windows capture and desktop output before turning that question into a product claim.

The remaining blast radius is lifecycle, state, and build linkage

AreaReal failureLikelihoodCostRequired check
Render-host backend gateA null build links AppKit or a macOS build loses --render-host.MediumHighBuild null and macOS variants; exercise render-host argument parsing.
SDK runner startupCapture and normal null execution dispatch startup or shutdown in different orders.MediumHighOne shared helper plus event-order tests.
GPU frame driveThe command writes a valid clear-color PNG and exits zero.High until provenHighOpen output; compare against clear color; assert commands and nodes for visible examples.
Capture state rootThe command reads or mutates live widget storage, placement, logs, or provider state.MediumHighSeed the live store with a sentinel and prove capture leaves it byte-identical.
CLI routingCapture calls devWidget, registers the widget, or starts desktop services.MediumMediumSpy on registry, host, window, and IPC entry points; all remain untouched.
Automation reuseA second action implementation drifts from desktop input behavior.MediumMediumOne dispatcher test runs the same action through desktop automation and capture.
Production widget pathThe new environment branch changes startup, idle CPU, memory, or binary size when unset.LowHighDesktop tests plus before and after ReleaseFast binary and process receipts.
WidgetSession extractionNo change planned.ClearedNoneRevisit only after a measured blocker.
Public TSX SDKNo authoring API change in the first package.ClearedNoneExisting widgets compile unchanged.

Source: reproduced null-link failure, uniform-black prototype outputs, existing CLI routing, SDK runner and automation code, and Weaver's storage bootstrap.

Stop instead of shipping a convincing lie

  • Stop if a visible example matches its clear color even when the PNG parses and its dimensions are correct.
  • Stop if the receipt calls alpha coverage content. Transparent and opaque clear colors both make that number misleading.
  • Stop before adding a frame cap, wait timeout, latency target, or process-lifetime policy without the example-corpus receipt.
  • Stop if capture needs a second input dispatcher, snapshot schema, layout engine, or renderer.
  • Stop if capture reads the live storage root or connects the live provider channel without an explicit opt-in.
  • Stop if the Weaver commit points at a Native SDK commit that the remote cannot fetch.
  • Stop if a Linux-only run is reported as macOS or Windows end-to-end proof.
  • Stop if macOS or Windows parity is inferred from source instead of compared pixels.

The remote handoff is done only with these receipts

  • A fresh clone initializes the submodule and installs JavaScript dependencies with no local file copied in.
  • The null backend links on macOS, and the normal macOS render-host mode still builds.
  • Clock, text, image, interaction, timer, font, and provider cases produce inspectable artifacts.
  • Every capture prints one receipt with provenance, pixel facts, pending work, inputs, and stage timings.
  • The capture command leaves widget registration, desktop windows, host IPC, live storage, and live placement untouched.
  • An action script changes both semantics and pixels through the existing dispatcher.
  • The Native SDK commit is pushed before Weaver updates the submodule pointer.
  • Native SDK fast gate, full relevant tests, Weaver tests, type checking, and git diff --check pass.
  • Before and after ReleaseFast binary size and ordinary widget process receipts are attached.
  • The user-facing CLI change has its changelog fragment and skills/conjure-widget/SKILL.md teaches capture and inspection.
# Final remote verification
npm test
npm run typecheck

cd runtime
zig build test -Dplatform=null --summary all
cd native-sdk
zig build test --summary all
scripts/gate.sh fast
cd ../..

# Capture acceptance cases
node cli/bin/weaver.js capture examples/clock --out artifacts/clock.png
node cli/bin/weaver.js capture examples/styling-text --out artifacts/text.png
node cli/bin/weaver.js capture examples/styling-images --out artifacts/images.png
node cli/bin/weaver.js capture examples/pomodoro --action-file test/capture/pomodoro.actions --out artifacts/pomodoro-running.png

# Repository and submodule proof
git diff --check
git status --short
git -C runtime/native-sdk status --short
git diff --submodule=log

Source: Weaver package scripts, Native SDK agent guide, and the acceptance cases defined in this handoff. Proposed capture commands do not exist before implementation.

Raw evidence and proof level

Reproduced null-backend blocker
$ cd runtime
$ zig build -Dplatform=null -Dautomation=true -Doptimize=ReleaseFast --summary all
error: undefined symbol: _native_sdk_appkit_render_host_run
note: referenced by .../weaver-widget_zcu.o:_main.main

Build Summary: 3/6 steps succeeded (1 failed)

Reproduced 2026-08-24 on macOS with Zig 0.16.0 against Weaver 999ccfb; runtime code matches the evidence base because intervening commits changed CI files only.

Invalid prototype PNGs
# ffmpeg signal statistics for clock.png, pomodoro.png, and text.png
RGB luma: YMIN=16, YMAX=16
Chroma: UMIN=128, UMAX=128, VMIN=128, VMAX=128
Alpha: YMIN=255, YMAX=255

Result: every output is one opaque black color.
The corrected GPU event code was modified after these files were written.

Measured 2026-08-24 from the local prototype outputs in /tmp/wcap. These files are not required by the remote handoff.

Current code anchors
FactAnchor
Weaver builds the real app before calling the runner.runtime/src/main.zig:1239-1491
The render-host branch keys on host OS and references the missing symbol.runtime/src/main.zig:1242-1252
The runner selects session replay before a desktop backend.runtime/native-sdk/src/app_runner/root.zig:392-417
Session replay enables null GPU surfaces and screenshots.runtime/native-sdk/src/app_runner/root.zig:693-878
Null GPU surfaces and image decode default off.runtime/native-sdk/src/platform/null_platform.zig:220-245
A GPU view is rejected when null GPU support stays off.runtime/native-sdk/src/platform/null_platform.zig:910-914
macOS can install CoreText services without a window.runtime/native-sdk/src/platform/macos/root.zig:960-973
The automation server publishes snapshots and atomic screenshots.runtime/native-sdk/src/automation/server.zig:40-97
The session journal records events, effects, fingerprints, and screenshots.runtime/native-sdk/src/runtime/session_journal.zig
The screenshot uses the deterministic CPU reference renderer.runtime/native-sdk/src/runtime/canvas_frame.zig:895-956

All anchors refer to Weaver commit e69a0997c5a883a69514674fab7dfcdbe0016114 and Native SDK submodule commit 4c5c0999c2324b8dc2016625e85571e554b2484a.

proof level 3 The runner architecture, existing services, black-frame failure, and link blocker are confirmed. A remote agent must produce and inspect the first correct full Weaver PNG before raising this to level 4.

Revised 2026-08-24 · Codex for Dara · remote handoff inputs: Weaver e69a0997, Native SDK 4c5c0999, Opus review, reproduced null-link failure, black-frame pixel inspection, repository source, and prior test receipts · confidence: high on architecture, medium on implementation order, unproven on first valid full-widget capture · revision v2