Five streaming-product repos declare path = "../sibling" dependencies on crates and packages that live in separate GitHub repositories. This breaks single-repo CI: actions/checkout only pulls the current repo, so the path target does not exist and the build fails before lint runs.
Affected repos (2026-05-21)
| Consumer | Sibling | Kind |
|---|---|---|
openalice-live | @openalicelabs/ui | npm path |
openalice-voice | openalice-agent-protocol-rs | Cargo path |
openalice-rt | openalice-agent-protocol-rs | Cargo path |
openalice-social-api | openalice-agent-protocol-rs | Cargo path |
openalice-world | openalice-agent-protocol (TS) | npm path |
Three legitimate fixes
- Publish as packages — clean, idiomatic, versioned, but needs npm + crates.io accounts and a release process per sibling.
- Co-checkout in CI — one workflow tweak per repo, needs a PAT for private siblings, slightly slower CI.
- Git-URL deps (
git = "https://...") — no infra, but slower CI and every push to a sibling can break a consumer.
Recommended pattern: co-checkout
A reusable step that pulls the sibling repo into the parent directory of the current checkout, so the existing path = "../sibling" resolves without further config:
- uses: actions/checkout@v4
with:
repository: OpenAliceLabs/openalice-agent-protocol-rs
path: ../openalice-agent-protocol-rs
token: ${{ secrets.SIBLING_REPOS_PAT }}
fetch-depth: 1SIBLING_REPOS_PAT is a fine-grained GitHub Personal Access Token with Contents: Read on the sibling repos only. One PAT per consumer repo's secrets keeps blast radius bounded.
Why fine-grained PAT
A classic PAT grants org-wide write. A fine-grained PAT can be scoped to exactly the sibling repos with read-only access, which is the principle of least privilege the lab applies elsewhere (e.g. the INTERNAL_BROADCAST_SECRET
X-Internal-Secretscope rule for auth).
What this unblocks
Five CIs that have been red for days. Each red CI also masks real bugs in the consumer repo (see kb://learnings/2026-05-21-workspace-path-deps-unblock for the actual bugs surfaced once CI started running again).
Future migration path
When any sibling crate is mature enough to publish, the consumer's Cargo.toml swaps path = "../sibling" for version = "x.y.z" and the co-checkout step is removed. Until then, co-checkout preserves the local workspace dev ergonomics (single cargo check in the parent folder sees both crates) without the publish overhead.