Project Related Context - Capture the Sibling Repos (Deliberate)
You drive the deliberate capture of a project's related repositories, and you own both tiers of the house related-projects model:
.claude/rules/baseline-project-related-context.md- the generated AWARENESS rule: pathless, so it loads every session and every subagent - the minimum that makes the siblings exist for the agent (name / location / relation / seam), plus the trigger to read the doc when a task touches a seam.<docs-path>/related-context/PROJECT-RELATED-CONTEXT.md- the on-demand ORIENTATION doc: the full entries includingfirst_readand the evidence behind each relation and seam, read when actually working near a seam. Its folder<docs-path>/related-context/is the ONE home for every doc tied to a sibling repo - cross-repo plans, change requests, issue notes, a sibling's run recipe - filed there by any session that produces one; a location outside the root takes the user's explicit approval first, per the docs-root baseline. This capture owns only the orientation doc: the other files in the folder are working papers it never rewrites or prunes.
Both are generated files; a re-run refreshes both in place. The rule's name is deliberately NOT in the stack installer's fetch manifest (and never may be - a fetch would overwrite the generated copy) and nothing prunes the rules directory, so both survive stack update. Under the default layout both are machine-local (.claude/* is gitignored and the docs root defaults inside it) - a fresh clone re-runs the capture; only a committed docs root ships the doc with the repo.
Args-driven, never a scan. The user names the related projects - local paths or git URLs, optionally with a relation hint each (../backend, git@github.com:org/shared-contracts.git provides-to). In-repo sub-projects are siblings too: ./server, ./client in a monorepo are valid locations, and their entries give project-solve-cross-task the dependency direction for producer-first ordering. No args: ask for them via AskUserQuestion (free text via Other - never options scraped from a filesystem scan; a plain-text ask where the harness lacks the tool) and stop. Do not guess at siblings from the filesystem.
Execution modes
DELEGATED vs INLINE keys on dispatch capability, not file presence. When dispatch is available (and the seat exists), ask ONE question before the fan-out, via AskUserQuestion - characterize the siblings via related-project-analyzer seats (recommend it: the seats absorb the reads), or in-session? - then pick once, hold for the run:
- DELEGATED (the user chose seats) - fan out related-project-analyzer per sibling as below; you merge and write.
- INLINE (chosen - or forced, no question asked: no dispatch (Cursor), or the related-project-analyzer seat is absent, which this opt-in capture must tolerate: it ships outside the always-installed baseline, so a project can carry the skill without the seat) - do the same characterization in-session, one sibling at a time, honoring the agent's own rules (both-sides cross-reference evidence, verified first_read, 3 locating passes, UNVERIFIED over fabrication; a URL sibling is shallow-cloned to scratch and removed after) - then continue at MERGE identically.
The run
0. MODE - the one ask
Resolve the Execution modes question above NOW, via AskUserQuestion, before anything else in this run - the ask is a numbered step because a preamble-only ask gets skipped straight past to the fan-out (measured: one run dispatched 4 seats with zero asks). One exception: a bare invocation with no args fires the Inputs no-args ask INSTEAD and stops - there is nothing to pick a mode for yet; when both questions are open they join the same AskUserQuestion call.
1. VALIDATE - the arg list
For each location: a path must exist (relative resolved from the project root), a URL must look like a git remote. An invalid location is reported and skipped, never silently dropped. Note each relation hint - it travels to the agent as a prior, not a verdict.
2. FAN OUT - one related-project-analyzer per sibling, in parallel
Dispatch all seats in a single message. Each dispatch prompt carries: the HOST project's root and identity (name + package/assembly ids - read them once from the manifest files first), ONE sibling location, and its hint if given. The agents write no files; their final messages - one YAML entry + evidence + uncertainty each - are your merge input. An agent returning UNVERIFIED fields is a valid result: both tiers record what could not be read.
3. MERGE - write /related-context/PROJECT-RELATED-CONTEXT.md
Create <docs-path>/related-context/ when absent. Legacy layout: a PROJECT-RELATED-CONTEXT.md sitting at the docs root itself (the pre-folder home) is MOVED into the folder first and reconciled there - never left behind as a stale twin. Consolidate into one doc - apply the markdown-style skill so it reads as a quick reference. Shape:
- The
Captured: <branch>@<short-sha>, <date>lifecycle stamp, then one opening line - what the doc is: the durable orientation detail for cross-repo work; the always-loaded awareness minimum lives in the generated rule; dynamic findings go to the MCP that holds cross-project recall, never here (none registered: they stay session-local). Stamp nuance for THIS doc: the entries describe the SIBLING repos as read on that date - the date is the staleness signal (siblings drift on their own), while this repo's branch matters little; re-running the capture for a sibling upserts its entry, which is this doc's whole update path. - The entries - one
related_projects:YAML block, the house schema per sibling:
related_projects:
- name: <sibling name>
location: <path or git URL>
relation: consumes | provides-to | peer | depends-on | embeds
first_read: [<docs-path-from-sibling-root-to-read-before-working-a-seam>]
seam: <the shared surface a change here can break there - API, package, schema>
captured: <branch>@<short-sha>, <date>
- Per sibling - a short evidence note under its own heading: what grounds the relation and seam (the located files, both sides), plus any uncertainty or UNVERIFIED marker carried over verbatim. Keep each note lean - orientation, not an audit.
A filled entry looks like:
related_projects:
- name: acme-billing-api
location: ../acme-billing-api
relation: provides-to
first_read: [docs/architecture/ARCHITECTURE.md]
seam: the OrderCreated contract in src/Contracts - this repo publishes, billing consumes
captured: develop@a1b2c3d, 2026-07-24
Each entry carries its own captured: <branch>@<short-sha>, <date> - entries are upserted at
different times, so provenance is PER ENTRY here; the doc-wide stamp from point 1 only records
the LAST run, never stands in for an entry's own. It matters most for a relationship
born on a feature branch (the seam code exists only there): on any other branch that entry is a
claim from elsewhere - verify the seam exists before relying on it. Re-running the capture for
that sibling after the branch merges refreshes the entry with the base branch's stamp.
4. RULE - write .claude/rules/baseline-project-related-context.md
The awareness tier, generated from the same entries - a valid PATHLESS rule (frontmatter with a description: and NO paths:, so it is always-on). Keep it to the awareness minimum; describe edges, not roles:
---
description: Related projects awareness - generated by /project-related-context; edit via a re-run, not by hand.
---
# Related projects
This repo is one of several that make up a product. The siblings, the edges that bind them:
<related_projects yaml block - name / location / relation / seam per sibling (NO first_read - that
detail is the doc's job); an entry captured on a branch OTHER than this repo's base branch gets one
trailing marker `(captured on <branch>)` - dropped when a base-branch re-capture refreshes it - so
a session on another branch knows that edge may not exist in its code>
- Everything past awareness - first_read, the evidence behind each seam - lives in
`<docs-path>/related-context/PROJECT-RELATED-CONTEXT.md`; read it when a task touches a seam.
The same `<docs-path>/related-context/` folder holds every other sibling-repo doc (cross-repo
plans, change requests, run recipes) - check it before re-deriving sibling state, and file
new sibling-repo docs there, never elsewhere.
- serena binds to THIS repo: Read/Grep a sibling directly, but symbol-navigate it only from a
context rooted there.
- Dynamic cross-repo findings go to the MCP that holds cross-project recall, never a committed
file; with no such server registered they stay session-local.
Create .claude/rules/ when absent. The rule is regenerate-only: entries come from the reports, the three closing bullets are fixed - never hand-edit the copy, never let the rule grow evidence or first_read detail (always-on tokens are paid every session and every subagent; the fat stays in the doc).
Re-run is an upsert, keyed by location, in BOTH files. A sibling passed this run: its entry (and doc note) rewritten from the fresh report. An existing entry whose location was NOT passed: kept exactly as-is (removal is a manual edit - report which entries you left untouched so stale ones are visible). Both files converge; they never accumulate duplicates, and their entry sets never drift apart - the same run writes both.
5. REPORT
Confirm both artifacts (rule created/refreshed + entry count; doc created/refreshed + entries rewritten vs kept; any location skipped as invalid or UNVERIFIED). State where each landed - machine-local under the default layout, shipped with the repo only when the project set a committed docs root. No re-paste of either body - point to the files.
Handing work to a sibling project
A session belongs to ONE project. When work here needs a change THERE - a sibling repo, a consumed
package, a related service - investigate freely (read its code, run its tests read-only, find the
exact symbol) and then HAND IT OFF: guard-cross-project-write.js blocks the write, and the reason
is not tidiness. A change applied from here skips that repo's tests, conventions, review and
release, and the project that owns it never sees it happen.
Write the card at <docs-path>/cross-project-tasks/<other-project>.md, appending to it rather than
replacing it, one section per task:
- What must change, and where - the file and symbol you located, not 'somewhere in the auth layer'. This is what the investigation is for.
- Why this project needs it - the concrete failure or limitation on this side.
- The contract - the shape both sides must agree on (a signature, an endpoint, a payload, a version floor). If it is not stated here, both sides will guess differently.
- How that side verifies it - the test or check that proves it landed.
Then finish YOUR side against the other project's CURRENT behaviour, or state plainly what stays blocked until the card is done. Do not leave this project half-changed against a version of the sibling that does not exist yet.
Don't game it
Every entry is grounded in the agent's located evidence or carries its UNVERIFIED marker into both tiers - a relation is never smoothed over, a hint never overrides contradicting evidence silently (the contradiction is reported), a first_read never lists a doc that was not verified to exist. Unreachable siblings stay in both files as UNVERIFIED entries, not silently dropped - the reader deserves to know a seam exists even when it could not be read.