fix(#434): route CLAUDE.md SETUP step 1 onboarding.yaml through portfolio helper#437
Conversation
The CLAUDE.md SETUP step 1 told agents to "Read onboarding.yaml" without qualifying which repo to read from. In single-fork mode this resolves correctly (the fork is the only candidate); in split-portfolio v2 mode Claude resolves against $PWD (the public fork root), which holds the template-default onboarding.yaml, while the adopter's fully-configured copy sits in the private sibling repo and is silently ignored. The portfolio_onboarding_path helper has shipped in _lib-portfolio-paths.sh since #242, but CLAUDE.md's session-start instruction never started using it. This patch wires SETUP step 1 to source the helper and resolve onboarding via portfolio_onboarding_path, mirroring the bash snippet pattern already used in skills like /inbox and /tasks. In single-fork mode the helper returns <ops-root>/onboarding.yaml — same file the previous instruction reached. The indirection only matters in split-portfolio v2 mode but costs nothing to apply unconditionally. Closes #434. ## Glossary | Term | Definition | |------|------------| | portfolio_onboarding_path | Resolver in _lib-portfolio-paths.sh that returns the onboarding.yaml path: <ops-root>/onboarding.yaml in single-fork mode, <sibling>/onboarding.yaml in split-portfolio v2 mode. Sibling pattern to portfolio_registry / portfolio_projects_dir / portfolio_workspace_dir. | | Split-portfolio v2 | The two-repo mode (public framework fork + private sibling) introduced by the /split-portfolio skill, where adopter-private configuration lives in the sibling and the fork remains shareable. | | Single-fork mode | The original out-of-box mode where one fork holds both framework and adopter config. portfolio_*_path helpers resolve to the fork in this mode. | Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
atlas-apex
left a comment
There was a problem hiding this comment.
Code Review: PR #437
Commit: a0ea355bbb29d65b5f5515d2c88991c0df51eccf
Summary
Routes the SETUP step 1 instruction in CLAUDE.md through the existing portfolio_onboarding_path helper in .claude/hooks/_lib-portfolio-paths.sh. The helper has correctly resolved sibling vs fork onboarding paths since #242, but the verbatim "Read onboarding.yaml" instruction at session start kept resolving against the public fork — picking up template defaults in split-portfolio v2 mode. Ten-line additive doc tweak; zero code change.
Checklist Results
- N/A Architecture & Design (doc-only)
- PASS Code Quality — bash snippet matches the documented usage pattern at lines 11–12 of
_lib-portfolio-paths.sh.git rev-parse --show-toplevelis the right anchor for sourcing the helper from any session cwd inside the fork. - PASS Testing — the helper's v2 behaviour is already covered by
.claude/hooks/tests/test_portfolio_paths.shcases at lines 319–362 (in-fork default + sibling override). No new tests required since no logic changed. - N/A Security (no auth, no secrets, no PII surface)
- N/A Performance
- PASS PR Description & Glossary — three-row glossary covers
portfolio_onboarding_path, split-portfolio v2, single-fork. Closes link present. "Why this matters" prose explains the silent-template-defaults failure mode well. - PASS Summary Bullet Narrative — bold label + em-dash rationale shape is the recommended form, not the label-only anti-pattern.
- N/A Technical Decisions (AgDR) — routing through an already-shipped helper isn't a new decision. The original resolver lives in #242; no new library, framework, pattern, or architecture introduced by this diff.
- N/A Adopter Handbooks — diff is
CLAUDE.mdonly; noarchitecture/,general/, or language-trigger paths matched.
Issues Found
None blocking on the diff itself.
Suggestions
-
CI advisory — lychee failure is unrelated but blocks merge per
.claude/rules/pr-quality.md§ "No Red CI Before Merge". Thelycheelink-check failed on a network error reachinghttps://www.conventionalcommits.org/referenced indocs/spikes/local-model-routing.md— a file this PR does not touch. The rule is intentionally strict ("even if the failure is pre-existing or unrelated"). Two paths forward before the human approver merges:- Retry the lychee workflow (transient network errors typically clear on rerun).
- If it persists, file a follow-up to either (a) add
conventionalcommits.orgto the lychee exclude list in the link-check workflow, or (b) replace the bare URL in the spike doc with the GitHub-archived version. Then rebase / push an empty commit on this branch to re-trigger CI.
-
Optional doc nit (non-blocking). The bash snippet's comment line reads
# Read "$onboarding" with the Read tool. Could be slightly clearer as# Then read "$onboarding" with the Read toolso a sequential reader doesn't pause on whether the snippet itself is supposed to do the read. Truly minor; do not block on this.
Verdict
APPROVED (diff) — the single-line routing change is correct, consistent with the helper's documented usage, and addresses #434's silent-template-defaults bug cleanly. Per the no-red-CI rule, the lychee failure still needs to clear before a human approver should run /approve-merge 437; that is a CI infrastructure concern, not a code-quality blocker on this PR.
Reviewed by Rex (Code Reviewer Agent)
Reviewed commit: a0ea355bbb29d65b5f5515d2c88991c0df51eccf
#437) The CLAUDE.md SETUP step 1 told agents to "Read onboarding.yaml" without qualifying which repo to read from. In single-fork mode this resolves correctly (the fork is the only candidate); in split-portfolio v2 mode Claude resolves against $PWD (the public fork root), which holds the template-default onboarding.yaml, while the adopter's fully-configured copy sits in the private sibling repo and is silently ignored. The portfolio_onboarding_path helper has shipped in _lib-portfolio-paths.sh since #242, but CLAUDE.md's session-start instruction never started using it. This patch wires SETUP step 1 to source the helper and resolve onboarding via portfolio_onboarding_path, mirroring the bash snippet pattern already used in skills like /inbox and /tasks. In single-fork mode the helper returns <ops-root>/onboarding.yaml — same file the previous instruction reached. The indirection only matters in split-portfolio v2 mode but costs nothing to apply unconditionally. Closes #434. ## Glossary | Term | Definition | |------|------------| | portfolio_onboarding_path | Resolver in _lib-portfolio-paths.sh that returns the onboarding.yaml path: <ops-root>/onboarding.yaml in single-fork mode, <sibling>/onboarding.yaml in split-portfolio v2 mode. Sibling pattern to portfolio_registry / portfolio_projects_dir / portfolio_workspace_dir. | | Split-portfolio v2 | The two-repo mode (public framework fork + private sibling) introduced by the /split-portfolio skill, where adopter-private configuration lives in the sibling and the fork remains shareable. | | Single-fork mode | The original out-of-box mode where one fork holds both framework and adopter config. portfolio_*_path helpers resolve to the fork in this mode. | Co-authored-by: me2resh <ahmed.abdelaliem@gmail.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
portfolio_onboarding_path— the resolver already exists in_lib-portfolio-paths.sh(since [Feature] Split-portfolio v2: workspace + onboarding move to private repo, plus /update migration #242), but the session-start instruction kept telling agents to "Readonboarding.yaml" verbatim. In split-portfolio v2 mode that resolves against the fork root (template defaults) instead of the sibling (fully-configured). One adopter-visible doc tweak; zero code change.Why this matters
Every session starts with the SETUP block. If step 1 picks up template defaults —
"Your Company Name",tool: "GitHub Issues",ticket_prefix: "GH"— every downstream role activation, ticket creation, and PR workflow operates on wrong company / tracker config. In single-fork mode this never fires (one repo, one onboarding.yaml). In split-portfolio v2 mode the silently-wrong-defaults bug bites every session.The helper has been right for ~3 releases; only the instruction lagged.
Testing
portfolio_onboarding_pathreturns<ops-root>/onboarding.yaml(unchanged behaviour)<sibling>/onboarding.yaml(the adopter's filled-in copy).claude/hooks/_lib-portfolio-paths.shor.claude/hooks/tests/— the helper logic itself isn't touched, only the instruction that drives Claude to use itCloses #434.
Glossary
portfolio_onboarding_path_lib-portfolio-paths.shthat returns the onboarding.yaml path:<ops-root>/onboarding.yamlin single-fork mode,<sibling>/onboarding.yamlin split-portfolio v2 mode. Sibling pattern toportfolio_registry/portfolio_projects_dir/portfolio_workspace_dir./split-portfolioskill, where adopter-private configuration lives in the sibling and the fork remains shareable.portfolio_*_pathhelpers resolve to the fork in this mode.