Bootstrap-BareRepo.ps1 for fresh-clone onboarding (#420) - #441
Merged
Conversation
Sister script to Migrate-ToBareRepo.ps1: that one converts an existing
operator clone; this one starts from nothing and produces the canonical
bare-repo + per-run-worktree layout in a single step.
Signature:
Bootstrap-BareRepo.ps1 -RemoteUrl <url>
[-ParentDir <path>] # default: ~/projects
[-RepoName <name>] # default: derived from URL leaf
[-MainBranch <name>] # default: remote HEAD (queried post-clone)
[-Commit] # default: dry-run
Behavior:
- Classifies state up front: full_bootstrap | recover_missing_main |
recover_missing_runs | already_bootstrapped | refused. Dry-run mode
prints the classification + the plan it would execute.
- Idempotent: re-running on a canonical layout is a no-op success.
- Narrow partial-state recovery: bare present + main missing -> add the
missing worktree; bare + main present + runs missing -> just mkdir.
Both gated on the bare's `origin` URL matching `-RemoteUrl` after
conservative normalization (trailing `/` + trailing `.git` stripped,
case-insensitive). https <-> ssh forms are NOT considered equivalent.
- Refuses (exit 3) on identity mismatches and pre-existing collisions:
bare path that isn't bare, main path with a different `--git-common-dir`,
target branch already checked out in another worktree, empty/unborn
remote, non-directory at the runs path.
- Always probes via `git --git-dir=<bare>`, never `git -C <bare>` —
works under `safe.bareRepository=explicit`.
- No `-Force` switch: identity mismatches and path conflicts are always
fatal because there is no equivalent of the legacy-clone-preserved
side door that Migrate-ToBareRepo has.
Tests: 31 Pester tests, real `git init` in temp dirs, no mocks. Covers
URL parsing for https/ssh/ssh-shortcut/ADO/local-file forms; default-
branch detection (main/master/explicit override); idempotency; both
recovery paths; six refusal cases; dry-run; and preflight failures.
Wiring:
- install.ps1 fetches it into ~/.polyphony/bin/ alongside the other
launcher scripts (download loop + $expectedLaunchers list).
- polyphony-bootstrap skill § 2 and docs/onboarding-guide.md § 2 both
point at it for the fresh-clone case (Migrate stays as the
existing-clone path).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This was referenced May 17, 2026
PolyphonyRequiem
added a commit
that referenced
this pull request
May 17, 2026
) (#447) Seven small fixes across `polyphony-runtime`, `polyphony-bootstrap`, and `docs/onboarding-guide.md` that close the epic-414 onboarding friction tracked in #425. Consolidated because each is a one-line to one-paragraph change and they all hit the same three documents. 1. polyphony-runtime: removal of `twig list-workspaces` reference. Verified the in-repo skill already uses the correct `twig workspace` verb — the operator's report was against a stale copy. No change required. 2. polyphony-runtime: disambiguate "repo root" vs "main worktree". The decision-tree question now asks whether `.polyphony-config/` is in the **main worktree** (the `./<repo>/` checkout under the bare-repo + worktree layout) rather than ambiguously "in the repo root". A new admonition at the top of the preflight section spells out that all polyphony commands — and the launcher — must run from inside the main worktree, not the bare-repo root. 3. polyphony-bootstrap: document the `safe.bareRepository=explicit` Windows pitfall. Added a sub-bullet to § 2 explaining that plain `git -C <repo>.git ...` is rejected with the `safe.bareRepository is 'explicit'` error on Microsoft-managed boxes, and showing the `--git-dir=<repo>.git` form. Notes that `Bootstrap-BareRepo.ps1` and `Sync-BareRepo.ps1` already use the correct form — the pitfall only bites raw `git` calls by hand. 4. polyphony-bootstrap: call out `twig init --force` when the repo ships a `.twig/config` (twig's own repo does this). New blockquote in § 1 right after the existing `twig init` recipe. 5. polyphony-bootstrap: fix `twig process $type` → `twig process --type $type` in three places (§ 3.5 command, § 4 walk-every-event command, § 6 checklist line). Added a blockquote at § 3.5 explaining that twig 0.77+ requires the flag form even though twig's own help still shows the positional form (the upstream inconsistency). 6. polyphony-bootstrap: add a "how to pick a smoke-test work item" recipe to § 1. `twig workspace --tree` is empty on a fresh sprint, so the recipe now also offers `twig query --state Doing` and `twig query --state "To Do" --type <leaf-type>` as sprint-pin-free fallbacks. 7. onboarding-guide § 4 "What Gets Generated": update the directory tree to show the per-role agent-guidance layout (`architect.md`/`coder.md`/`reviewer.md`) the bootstrap actually emits, instead of the stale per-type layout (`epic.md`/`user-story.md`/`task.md`). Replaced the stale note below the tree with an accurate description of the per-role + optional per-role-per-type refinement layout, with a pointer to § 7 for the per-role vs all-agents authoring contract. Verification: - `pwsh ./tests/lint-type-agnostic.ps1` — PASS (57 files scanned across surface 'all'; placeholder `<Type>` / `<leaf-type>` used in twig recipes to avoid the lint). - All other Pester lints green (lint-pwsh-jinja-bareword, lint-prose-children, lint-sync-after-mutation, lint-version-drift, lint-no-tracked-polyphony-state, etc.). - One pre-existing `lint-psscriptroot-paths` finding on `Bootstrap-BareRepo.ps1:79,140` (from PR #441) reproduces on `main` and is unrelated. Closes #425. Co-authored-by: Daniel Green <dangreen@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
12 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #420.
Adds
scripts/Bootstrap-BareRepo.ps1, the sister script toMigrate-ToBareRepo.ps1.Migrateconverts an existing operator clone;Bootstrapstarts from nothing and produces the canonical bare-repo + per-run-worktree layout in a single step.This closes a long-standing onboarding gap: the polyphony-bootstrap skill checklist and
docs/onboarding-guide.md§ 2 both assumed the operator already had a normal clone they could migrate. Fresh onboardings ("clone a repo for the first time and set it up bare") had to follow the manual recipe indocs/per-run-worktree-layout.md— and that recipe trips onsafe.bareRepository=expliciton Windows unless the operator already knows the--git-dirworkaround.Signature
Design highlights
State classification up front. Every invocation computes one of
full_bootstrap | recover_missing_main | recover_missing_runs | already_bootstrapped | refusedbefore doing anything destructive. Dry-run prints the classification + the plan. Tests assert each classification's output.Idempotency. Re-running on a canonical layout is a no-op success. Narrow partial-state recovery is supported:
git fetch --prune originthen add the missing worktree on the bare's HEAD branchmkdirthe runs rootBoth recovery paths are gated on the existing bare's
originURL matching-RemoteUrl(conservative normalization: strip trailing/and trailing.git, case-insensitive; does not equate https with ssh forms).Identity verification. Main-worktree validity is double-checked:
git -C $main rev-parse --path-format=absolute --git-common-dirmust point at the bare, AND the bare'sworktree list --porcelainmust include the main path. Both directions must agree.Refusals (exit 3, no
-Forceoverride).originor a mismatchedoriginworktree addso the error is clear)There is no
-Forceswitch — unlikeMigrate-ToBareRepothere's no legacy-clone-preserved fallback that would justify bypassing identity checks.Windows safety. Every probe against the bare uses
git --git-dir=<bare>rather thangit -C <bare>. Works undergit config --global safe.bareRepository explicit(the global default on my box, and the upstream-recommended hardening).Tests
31 Pester tests in
scripts/Bootstrap-BareRepo.Tests.ps1, realgit initin temp directories — no mocks for git itself. Mirrors the pattern inMigrate-ToBareRepo.Tests.ps1. Covers:.git/ https with trailing//git@host:ssh shortcut /ssh:/// ADO/_git// Windows file paths / emptyTest-RemoteUrlMatchequivalence (positive + negative cases, including the deliberate https-vs-ssh non-equivalence)-RepoNameis omittedmaindefault branch detection (master)-MainBranchoverride beats auto-detect (develop)All 31 pass locally (~40s).
Other wiring
install.ps1— added to both the download loop and the$expectedLaunchersverification list so it lands in~/.polyphony/bin/alongside the rest..github/skills/polyphony-bootstrap/SKILL.md§ 2 — one-line addition pointing atBootstrap-BareRepo.ps1for the fresh-clone case (and atMigrate-ToBareRepo.ps1for the existing-clone case).docs/onboarding-guide.md§ 2 — new "Fresh clone (no existing local checkout)" subsection with the canonical invocation and a note aboutsafe.bareRepository=explicit.Out of scope
Verification
install.ps1is structurally unchanged — same loop, one extra string in two lists.