Repository navigation
Family workstation layout: a plain <Family>/ folder holding the holder and the members' working clones — family.py init lands there, the scaffold learns --family, the holder gains a siblings utility that warns and never moves #76
Description
Lane: xfactory-2 (xFactory-2)
Governing record for a workflow change: the family's WORKSTATION LAYOUT — a plain parent folder named after the family, holding the holder clone and the members' working clones as siblings — becomes something the tooling places and checks, never something it moves. Design only at this stage; nothing here is claimed for authoring yet.
Where this comes from
The ruling that created families (Brett Heap, 2026-09-04): "InkRouter is only something that can download all the others easily? like a holder FOLDER and some utilities for the family of services." The implementation made the holder a REPOSITORY that pins member assembly roots as submodules under members/. The plain folder in the ruling's words was never written down — and it exists anyway, arranged by hand:
~/projects/InkRouter/ a plain folder, not a git repository
InkRouter/ the holder (InkRouter/InkRouter): family.yaml, members/IRRS, members/IRSS pinned + detached
IRRS/ working clone of InkRouter/IRRS, on main — where the lanes work
IRSS/ working clone of InkRouter/IRSS, on main
IRRS-worktrees/… a linked worktree of IRRS
session-handoff-2026-09-08-lane-*.md lane handoffs (lane-collision-protocol Rule 4's estate folder)
Two copies of each member on disk is correct and intended: the holder's members/<Project> is a pinned, detached checkout for make bootstrap and make validate; development happens in the sibling clone on its tracking branch, and the family is bumped to follow. Nothing documents this, and the first question a reader asks — "is InkRouter/InkRouter the family, and what is the parent folder?" — was asked today (2026-09-09).
What the tooling does today
scripts/family.py initmaterializes the holder in a TEMP directory unless--work-diris passed (work_root / family), so the person arranges the folder afterwards by hand.setup.sh/setup-project.pyland a new project beside where the person stands (--into= invocation directory, setup.sh self-bootstrap clones the new project into /tmp/<Project>: PARENT defaults to .. of the TEMPORARY checkout #39). No family awareness:grep -i family setup-project.pyfinds nothing.- The holder template (
templates/family-root/) hasbootstrap.pyandvalidate-family.py. There is no utility that produces the working clones beside the holder — the "download all the others easily" of the ruling is answered only by submodules inside the holder.
The proposal
Place at clone time; check afterwards; never move.
family.py initgets a real landing spot. Default: create<into>/<Family>/where the person stands and clone the holder INSIDE it, at<Family>/<Family>— the same "lands where you were standing" rule setup.sh self-bootstrap clones the new project into /tmp/<Project>: PARENT defaults to .. of the TEMPORARY checkout #39 gave projects.--work-dirstays as the override. Refuse (no--force) if<Family>/<Family>exists and is non-empty, as today.- The scaffold learns
--family <Name>.openRepoShape IRTS --org InkRouter --family InkRouterlands the new project at<Family>/IRTS, creating<Family>/if absent, and the "next commands" block ends with thefamily.py addline. Detection, advisory only: when the invocation directory is<X>/and<X>/<X>/family.yamlexists withname: <X>, the plan says "you are standing in the family folder; the project lands beside the holder" — no flag needed, nothing else changes. - The holder gains the missing family utility. A Makefile target in
templates/family-root/(name to decide —make siblings?make workstation?) that, for each row infamily.yaml, clones the member as a standalone working copy at../<Project>on its tracking branch, idempotently (an existing clone is fetched, never reset), and prints the layout. Creates nothing on GitHub; needs the same read credentialmake bootstrapneeds. When the holder's parent folder is NOT named<Family>, it WARNS and prints themvfor the human to run — the doctor pattern, not a mover. It never moves anything itself. - The layout is documented in the family-root README (and the openRepoShape README's Families section): the plain folder, the two copies and which one you work in, the doubled
<Family>/<Family>name and why it is kept, and where handoff files live.
Deliberately NOT proposed
A setup.sh in the holder that checks whether it is under a same-named folder and, if not, creates that folder and MOVES the checkout there. It relocates the directory out from under the shell, editors and every agent lane standing in it; it breaks linked worktrees, whose .git files carry absolute paths (~/.agents/AGENTS.md calls stale worktree pointers the canonical symptom); and it is the one thing this standard refuses everywhere else — an act done by surprise, where every refusal today names what to run instead. The warning-plus-mv in (3) gives the same outcome with the human's hand on it.
Open decisions
- The target's name in (3), and whether it also belongs in
scripts/family.py(run from a checkout of the standard) so it works before the holder is cloned. - Whether
--familyin (2) should also be honoured by native-Windowssetup-project.py(it should; same flag, same landing rule). - Keep the doubled
<Family>/<Family>clone name (recommended: the repository keeps its name andfamily.yamldisambiguates) or clone the holder under another local name.
Reach
Changes land in openRepoShape: scripts/family.py, setup-project.py (+ setup.sh/openRepoShape pass-through), templates/family-root/{Makefile,README.md,scripts/}, README, AGENTS.md, tests. Existing holders — InkRouter/InkRouter today — take the template additions through update-shape.py check / apply --add <path>, per file, on the human's word. Nothing changes for a project in no family.
🤖 Generated with Claude Code
Activity
brettheap commentedon Sep 9, 2026
Companion: #77 — continuing in-flight feature work on another workstation (
park/resumeover pushed branches, a per-user workspace manifest in a repository the person owns, handoffs that travel). Its point 5 makes the siblings utility proposed here the front half of rebuilding a whole estate on a fresh machine, so the two should be ruled on together.brettheap commentedon Sep 9, 2026
RULING for the family workstation layout (this issue), ANY lane — Brett Heap, 2026-09-09, walked through by lane xfactory-2 (xFactory-2) as multiple choice; each answer below is Brett's.
1a. The holder's target is
make siblings. It clones eachfamily.yamlmember as a working copy beside the holder, on its tracking branch, idempotently; warns and prints themvwhen the parent folder is not<Family>; never moves anything.1b. One implementation, two entry points. The utility lives in
scripts/family.pyin openRepoShape so it works before a holder is on disk; the holder's Makefile target calls the copied script. No second code path.2.
--family <Name>is honoured bysetup-project.py, so native Windows gets it by the same flag and the same landing rule assetup.shand theopenRepoShapecommand.3. The doubled
<Family>/<Family>layout stands. The holder clone keeps its repository name inside the family folder;family.yamldisambiguates; the README documents it.Unchanged from the body:
family.py initlands at<into>/<Family>/<Family>; the scaffold detects a family folder and says so in the plan; nothing ever moves a checkout.Rule 1 still decides who executes: claim here before authoring. Companion rulings on #77.
brettheap commentedon Sep 9, 2026
CLAIMED — lane xfactory-2 (xFactory-2), session harness 47c80b53-25d0-407b-8e19-432e9316bf61, 2026-09-09T15:40Z, for the whole of this issue as ruled above (RULING of 2026-09-09T15:16Z), in two pull requests: (A) the family side —
family.py initlanding at<into>/<Family>/<Family>,make siblingsimplemented once intemplates/family-root/scripts/and reached fromfamily.py siblings, the holder template and docs — branchfeat/family-siblings-and-init-landing; (B) the scaffold side —--family <Name>insetup-project.py(so Windows too), pass-through insetup.sh/openRepoShape, family-folder detection in the plan, docs — branchfeat/scaffold-family-flag. Brett Heap's word, 2026-09-09: "claim 76 and start on it".Reads before claiming:
gh pr list --repo opensoft/openRepoShape --state open: none.--state all --search 'siblings OR "--family" OR "family folder"': only merged history (v0.4: spec-only adoption seeds the empty leg; the FAMILY shape (a holder that pins member assembly roots) #16 introduced the family shape; adopt execute and family init set the xf-project-<id> topic, as the scaffold does #24, update-shape.py: the apply commit names the root's manifest, not project.yaml #47, update-shape.py: the no-shape refusal names the kind's manifest validator #52 touched family.py), nothing on this object.git ls-remote --heads origin | grep -i -E 'sibling|family-folder|scaffold-family|init-landing|076': none.brettheap commentedon Sep 9, 2026
(lane xfactory-2 (xFactory-2), 2026-09-09T16:20Z) PULL REQUESTS OPEN for the claim above: slice (B) the scaffold side — #78 (
feat/scaffold-family-flag, head c59c000); slice (A) the family side — #79 (feat/family-siblings-and-init-landing, head 1c094bd). The two grow README.md, AGENTS.md and the hygiene size caps at the same lines; whichever lands second is rebased by this lane before merge.docs/handbook.htmllags the README after #79 and is a follow-up, not part of this claim.siblings.py: the url normaliser strips any scheme by pattern rather t…
The scaffold learns --family: the clone lands at <into>/<Family>/<Pro…
Merge main (#78, the scaffold side of #76) into the family side: the …
siblings.py: a relative submodule url resolves against a backslash-se…
The family's workstation layout: init lands at <into>/<Family>/<Famil…
brettheap commentedon Sep 9, 2026
(lane xfactory-2 (xFactory-2), 2026-09-09T16:51Z) MERGED — both slices of the claim above, squash: #78 (the scaffold side,
--family) → 0170edd; #79 (the family side,family.py initlanding +make siblings) → b6df51b. Object complete. Follow-ups NOT part of this claim:docs/handbook.htmllags the README's Families section; the existing holder InkRouter/InkRouter takesscripts/siblings.pythroughupdate-shape.py check→apply --add scripts/siblings.pyon Brett's word.brettheap commentedon Sep 9, 2026
Closed on Brett Heap's word, 2026-09-09: "close 76". Rulings recorded above; both PRs merged (see the MERGED comment).
park/resume: a refused root is never bootstrapped, a leg off its trac…
park and resume as installed user commands: one word finds the estate…
family Makefile: `siblings`, `park` and `resume` refuse by name when …