kb://architecture/co-checkout-for-private-workspace-depsstable2026-05-21

Co-checkout pattern for private workspace path deps

architecturecigithub-actionsworkspacepath-depspat

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)

ConsumerSiblingKind
openalice-live@openalicelabs/uinpm path
openalice-voiceopenalice-agent-protocol-rsCargo path
openalice-rtopenalice-agent-protocol-rsCargo path
openalice-social-apiopenalice-agent-protocol-rsCargo path
openalice-worldopenalice-agent-protocol (TS)npm path

Three legitimate fixes

  1. Publish as packages — clean, idiomatic, versioned, but needs npm + crates.io accounts and a release process per sibling.
  2. Co-checkout in CI — one workflow tweak per repo, needs a PAT for private siblings, slightly slower CI.
  3. 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: 1

SIBLING_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-Secret scope 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.