Skip to content

[Refactor] Sweep SessionStart hooks to use _lib-ops-root.sh — fix split-portfolio v2 invisibility #302

@atlas-apex

Description

@atlas-apex

Driver

Surfaced 2026-05-19 during Rex review of PR #300 (the check-jq-installed.sh SessionStart hook for #280): the new hook uses the legacy onboarding.yaml-only walk-up to find the ops-fork root. That walk works for single-fork adopters (default) and for split-portfolio v1, but silently fails for split-portfolio v2 — under v2, onboarding.yaml lives in the private sibling repo, the public fork is anchored only by .apexyard-fork, and the walk-up condition fails. v2 adopters won't see the banner.

Audit of .claude/settings.json shows this isn't unique to check-jq-installed.shevery SessionStart entry except link-custom-skills.sh uses the legacy onboarding.yaml-only walk-up shape:

r=$PWD; while [ ! -f "$r/onboarding.yaml" ] && [ "$r" != / ]; do r=${r%/*}; done; exec "$r/.claude/hooks/<name>.sh"

This is legacy v1 behaviour that pre-dates the v2 anchor (.apexyard-fork) added in framework #242. The correct shape is to source _lib-ops-root.sh and call resolve_ops_root, which recognises both anchors (v2 marker first, legacy v1 pair as fallback).

Scope

Sweep every entry in .claude/settings.json under hooks.SessionStart (and any PreToolUse/PostToolUse entries that also do inline walk-up). Replace the inline walk-up shell with:

. "$(dirname "$0")/_lib-ops-root.sh" 2>/dev/null && \
  r=$(resolve_ops_root "$PWD") && \
  exec "$r/.claude/hooks/<name>.sh"

Or — if the hook itself uses _lib-ops-root.sh internally — drop the inline walk-up entirely and let the hook resolve from $PWD.

Audit the actual hook scripts too: any hook that does its own walk-up for ops-fork detection should source _lib-ops-root.sh instead of inlining the legacy two-file check.

Acceptance Criteria

  • Every SessionStart entry in .claude/settings.json resolves the ops-fork root via _lib-ops-root.sh (recognises both .apexyard-fork and the legacy v1 pair)
  • Same sweep for any PreToolUse / PostToolUse entries that inline the walk-up
  • Audit hook scripts for inline walk-ups (while [ ! -f "$r/onboarding.yaml" ]); replace with _lib-ops-root.sh usage
  • Split-portfolio v2 adopters get the same banners / hooks as single-fork adopters — verified manually by setting up a v2 layout locally
  • No regression for single-fork or split-portfolio v1 adopters
  • AgDR documents the sweep decision + the v2-aware shape as the canonical pattern for future SessionStart entries

Out of Scope

  • Adding new SessionStart hooks (this is a refactor of existing ones).
  • Changing the v1 fallback semantics — _lib-ops-root.sh already handles it.
  • A meta-hook that lints inline walk-up shells. The audit + sweep is one-time; future hooks will be caught in code review against the AgDR.

Risks / Dependencies

  • Risk: subtle behavioural change for adopters who somehow relied on the legacy walk-up silently failing on v2. Mitigation: the v2-aware walk-up is a strict superset — v1 conditions still match, plus v2 anchors. No legitimate adopter loses any functionality.
  • Risk: _lib-ops-root.sh itself has a bug that propagates across all SessionStart hooks. Mitigation: it's already in use by link-custom-skills.sh and the merge-gate hooks; well-tested. If anything, this sweep increases the bug surface area for that lib, making bugs in it land faster.

Glossary

Term Definition
Split-portfolio v2 Framework layout where onboarding.yaml + apexyard.projects.yaml + projects/ live in a private sibling repo (framework #242), with the public fork anchored only by .apexyard-fork
Walk-up The pattern of walking from $PWD toward / looking for a marker file that identifies the ops-fork root
_lib-ops-root.sh The shared library function resolve_ops_root <start_dir> that recognises both the v2 marker (.apexyard-fork) and the legacy v1 pair (onboarding.yaml + apexyard.projects.yaml)
Ops-fork root The top of the apexyard fork tree — where session state lives, where hooks resolve overrides from, and where v2's .apexyard-fork marker sits

Surfaced during Rex review of PR #300 on 2026-05-19.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium — plan-worthy, not urgentenhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions