Controlled Muse → GitHub mirror
R2 implements local preparation and delivery retry. The complete product and the held release candidate remain unfinished. R3 source reconciliation, integration review and combined installation/rollback follow. No real-project mirror or remote write is authorized by this document. Git-only operation remains a permanent choice; mirroring requires explicit R1 Muse adoption.
The current workflow replaces the old deploy script's implicit export/push. The
script and its template now delegate to the repository-bound ok mirror command.
There is no default source, target, remote, watch mode, automatic hook or push.
Reviewed input
Use an initialized Muse-authoritative source checkout, with main materialized at the approved revision and a separate, absent physical target path outside the source, its shared Muse store, and the kit installation. Its parent must exist. R2 creates a dedicated bare Git repository. It never exports onto a development worktree, clones a remote, adopts an existing Git directory, or removes foreign content. Even an existing empty directory is refused. Subsequent operations may reuse only that exact owned target and source/destination pair.
Save reviewed JSON under .overseer/local/approved-mirror.json. Required schema:
{
"schema": 1,
"source": {
"repo_id": "sha256:<64 lowercase hex digits>",
"branch": "main",
"revision": "sha256:<approved immutable revision>",
"hub_url": "https://staging.musehub.ai/OWNER/REPOSITORY"
},
"destination": {
"url": "https://github.com/OWNER/REPOSITORY.git",
"repository": "OWNER/REPOSITORY",
"branch": "muse-mirror",
"base": "main",
"expected_head": "absent"
},
"target": "/physical/isolated/mirror.git",
"expected_target": "absent",
"executables": ["path/to/approved-executable"]
}
The executable list must be sorted, unique, and contain exactly the projected executable paths. The source logical ID must match the existing R1 binding. The checkout UUID/root, kit runtime and separate Muse runtime are also checked. The plan's raw SHA-256 is a required command argument; an edited plan needs fresh review and a new digest. Source main and the full immutable revision must agree. A supplied approved revision is not a live observation of Hub acceptance.
First preparation requires both heads to be absent. For a later revision, set
expected_target to the current verified local mirror commit and expected_head
to the reviewed destination branch head (40 lowercase hex digits). Keep the same
plan and digest when retrying incomplete delivery. Changing the destination pair
or migrating an old mirror requires explicit reconciliation. R2 refuses historical
extra files/local bindings in an unowned target rather than silently deleting them.
The kit's existing remote mirror is consequently not ready to overwrite.
Prepare and verify locally
From the initialized source checkout, with the actual approved digest:
./.overseer/bin/ok mirror prepare \
--plan-file .overseer/local/approved-mirror.json --expect-plan PLAN_SHA256
./.overseer/bin/ok mirror verify \
--plan-file .overseer/local/approved-mirror.json --expect-plan PLAN_SHA256
./scripts/muse-bridge-deploy.sh prepare ... is an equivalent bound wrapper when
that script is installed. Old positional commit-message invocation fails. verify
is read-only, performs the real checks, and requires an already prepared commit;
it is not the native exporter's unchecked dry-run.
Preparation reads pinned Muse objects through the R1 read-only APIs and validates
all blobs, including excluded blobs. It does not invoke native git-export: that
version mutates source bridge files, runs bridge hooks, can skip missing objects,
and infers modes from shebangs. Git plumbing writes the exact projected tree with
no checkout, index, filters or inherited hooks. Each committed blob, mode and path
is compared with the approved source before the target ref is updated.
Projection excludes R1 config/launcher/local backups and inputs, canonical NEXT,
checkout-local .cursor/, all Git/Muse administration, .env and .env.*, and the
old local bridge sentinel. Actual excluded snapshot paths appear in the report;
ignore rules alone are not evidence. Templates and living summaries remain.
An old snapshot may contain local bindings; projection omits them without changing
Muse history. Normal adoption still refuses tracked local bindings under R1.
Supported files are regular, singly linked files. Working bytes must match the
snapshot, the shared stage must be empty, and source revision/config are rechecked.
Untracked source files are never copied. Source executable bits must agree with
the explicit list; Git modes are normalized to 100644/100755. Read/write
permission differences such as Muse's generated 0600 become 100644. Symlinks,
hardlinks and special permission bits are refused. A shebang is not mode authority.
Empty-directory metadata is reported and omitted because Git does not represent it.
The local projection limit is 32 MiB of blob bytes, with a 48 MiB helper-output cap
and 30-second helper deadline. These are explicit bounds, not full filesystem or
arbitrary Muse-domain fidelity.
Source bridge-hook configuration causes refusal and is preserved. Targets must have the exact engine-created Git config and no hooks or foreign entries. Global and environment Git configuration is isolated, and hooks are disabled on every Git command. Nothing installs or activates editor/Muse/Git hooks.
Separately authorized delivery and retry
Only after approving actual payload and named destinations, invoke mirror deliver
with the same plan arguments and an explicit physical --gh /path/to/gh executable.
No delivery was run against a real remote during R2. Preparation and verification
never contact remotes. Ordinary local status/next remain offline.
Delivery observes the exact public staging repository's JSON /refs response and
requires its code-domain repository ID and main revision to match approval. It
refuses unknown, moved or unpublished sources, redirects, unsupported hosts and
malformed responses. Authenticated/private MuseHub and production trust are outside
this adapter; there is no login, fingerprint reset or host fallback. The live server
protocol and publication rights remain unvalidated; fixture evidence is not remote
acceptance evidence.
It compares the explicit Git URL/branch head independently of whether export made a new commit, rechecks source/target/remote immediately before writing, uses a normal non-force push of the exact commit to the distribution branch, and reads back the head. A lost push response is resolved by readback. A stale remote stops for reconciliation; there is no force push or direct main publication. Git's push negotiation protects the ref update; these checks are not a cross-service atomic transaction and cannot freeze MuseHub/GitHub while an operation runs.
PR list/create/readback always specify the GitHub repository, head/base branches and target cwd. The PR must be open, from that repository, and at the exact mirror commit. Failure remains visible and retryable. Authentication/network/PR failures never erase a successful export or verified push. Retry first observes current state, skips only verified completed stages, and retries missing push/PR work.
Reports separate export, authority, push, and pr, with source checkout UUID,
physical roots, revisions, destination repository/branches, observed remote head,
and PR URL when verified. An ok preparation result means local preparation only;
its push/PR remain not_attempted and Hub remains unchecked offline.
One ordinary source-directory lock and target-parent lock serialize operators.
A single .overseer/local/git-bridge.json correspondence record binds this source
to one target/pair. Commit trailers bind source revision and exact plan digest.
No-change retry retains the Git SHA and record bytes. An interrupted record write
can recover from a verified commit with the exact parent/tree/trailers. A new source
revision with the same projection gets a correspondence commit with no file delta.
Interrupted preparation can leave unreachable local objects, but never publishes
an unchecked tree; ordinary rerun can finish. There is no new ledger or daemon.
The validation record contains actual local results and remaining R3 work.