User Story
As a split-portfolio adopter on GitHub Free who values the public/private separation, I want EVERY adopter-specific artefact to live in the private sibling repo — not just the registry + projects/ but ALSO onboarding.yaml (company info / tech stack / team) and workspace/<name>/ (cloned managed projects) — so that my public fork holds only stock framework files + my customisations to skills/hooks/rules. And as an EXISTING split-portfolio adopter, I want /update to migrate my layout for me, not require a hand-edit dance.
Acceptance Criteria
Architecture: extended portfolio config block
Ops-fork detection survives the move
Single-fork mode unchanged
Migration via /update
New adopters
Tests
Design Notes
Why this is a v1.4 ticket, not v1.3. v1.3 has 7 changes already queued. Adding this is real architecture work (touches portfolio paths, gitignore conventions, ops-fork detection, plus a destructive migration). Better to ship v1.3 with what's there and let this land in v1.4 with proper soak time.
The walk-up anchor question. Today's walk requires onboarding.yaml + apexyard.projects.yaml to find the public fork. After the move, both files are in the private repo. New anchor proposal: a presence-only marker file .apexyard-fork written by /setup at first run (or by /update during migration). Walk-up condition becomes: presence of .apexyard-fork (with optional fallback to legacy onboarding.yaml + apexyard.projects.yaml for un-migrated adopters during the transition window).
Symlinks in the public fork are not the answer. A naive "symlink onboarding.yaml from private repo" would mean the public fork's git status shows the symlink, plus the symlink target is OS-dependent. Better: the public fork has neither file; the framework code resolves through portfolio_onboarding_path() from the config block.
workspace/ in private repo is gitignored from the private repo too. Workspace clones have their own remotes and shouldn't be tracked anywhere — the private repo's .gitignore excludes workspace/*/ exactly the way the public fork does today.
Out of Scope
- Per-project handbooks layered over framework handbooks (separate ticket — v3 of split portfolio if ever needed)
- Migrating from single-fork to v2 split-portfolio —
/split-portfolio skill already exists for that direction; this ticket is about moving v1 split-portfolio adopters to v2
- Encrypted
onboarding.yaml or any other crypto on top of the gitignore (out of scope; gitignore is the boundary)
- Inside-gitignored layout (one directory holding both repos) — explicitly de-scoped per the conversation that motivated this ticket; sibling layout stays. v2 is purely about WHAT lives in the private repo, not WHERE the private repo sits relative to the public fork.
Effort Estimate
TBD — likely 1-2 days for the architecture + migration, plus tests + docs.
User Story
As a split-portfolio adopter on GitHub Free who values the public/private separation, I want EVERY adopter-specific artefact to live in the private sibling repo — not just the registry +
projects/but ALSOonboarding.yaml(company info / tech stack / team) andworkspace/<name>/(cloned managed projects) — so that my public fork holds only stock framework files + my customisations to skills/hooks/rules. And as an EXISTING split-portfolio adopter, I want/updateto migrate my layout for me, not require a hand-edit dance.Acceptance Criteria
Architecture: extended portfolio config block
.claude/project-config.json→portfolioblock accepts two new keys:onboarding— path toonboarding.yamlin the private repo (default../<fork>-portfolio/onboarding.yaml)workspace_dir— path to the workspace dir in the private repo (default../<fork>-portfolio/workspace)_lib-portfolio-paths.shexposesportfolio_onboarding_pathandportfolio_workspace_dirhelpersonboarding.yamlor writes toworkspace/<name>/resolves through the helpers (audit the codebase:/setup,/handover,/status,/inbox,/projects,/tasks,onboarding-check.sh, ops-root detection)Ops-fork detection survives the move
_lib-ops-root.sh(and the existing inline walk in 6+ hooks) currently requires BOTHonboarding.yamlANDapexyard.projects.yamlto be present at the candidate dir. After the move, neither file is in the public fork. Walk-up needs a new public-fork anchor (proposal: marker file.apexyard-forkthat the framework writes at first/setup)Single-fork mode unchanged
portfolioblock) see ZERO behaviour change.onboarding.yamlandworkspace/stay in the fork. No migration prompted.Migration via
/update/updatedetects split-portfolio adopters whose layout is pre-v2 (onboarding.yaml+workspace/in the public fork)onboarding.yaml→ private repo, gitignore in public forkworkspace/contents → private repo, gitignore in public forkportfolio.{onboarding,workspace_dir}keys to.claude/project-config.jsonAND the.apexyard-forkmarker/update --dry-run), backup branch on the public fork before commitsNew adopters
/setup --split-portfolio(or whatever the entry-point ends up being) creates the v2 layout from the start, no migration neededdocs/multi-project.md§ "Split-portfolio mode" updated to describe the v2 layout as the defaultTests
_lib-portfolio-paths.shtests cover the new helpers_lib-ops-root.shtest covers the new.apexyard-forkanchor/updatehas at least a smoke test (build a synthetic pre-v2 layout in a sandbox, run the migration, assert the new layout)Design Notes
Why this is a v1.4 ticket, not v1.3. v1.3 has 7 changes already queued. Adding this is real architecture work (touches portfolio paths, gitignore conventions, ops-fork detection, plus a destructive migration). Better to ship v1.3 with what's there and let this land in v1.4 with proper soak time.
The walk-up anchor question. Today's walk requires
onboarding.yaml+apexyard.projects.yamlto find the public fork. After the move, both files are in the private repo. New anchor proposal: a presence-only marker file.apexyard-forkwritten by/setupat first run (or by/updateduring migration). Walk-up condition becomes: presence of.apexyard-fork(with optional fallback to legacyonboarding.yaml+apexyard.projects.yamlfor un-migrated adopters during the transition window).Symlinks in the public fork are not the answer. A naive "symlink
onboarding.yamlfrom private repo" would mean the public fork'sgit statusshows the symlink, plus the symlink target is OS-dependent. Better: the public fork has neither file; the framework code resolves throughportfolio_onboarding_path()from the config block.workspace/in private repo is gitignored from the private repo too. Workspace clones have their own remotes and shouldn't be tracked anywhere — the private repo's.gitignoreexcludesworkspace/*/exactly the way the public fork does today.Out of Scope
/split-portfolioskill already exists for that direction; this ticket is about moving v1 split-portfolio adopters to v2onboarding.yamlor any other crypto on top of the gitignore (out of scope; gitignore is the boundary)Effort Estimate
TBD — likely 1-2 days for the architecture + migration, plus tests + docs.