diff --git a/tools/templates/consumer/__dot__claude/settings.json.tpl b/tools/templates/consumer/__dot__claude/settings.json.tpl index 5607d11a..346ea878 100644 --- a/tools/templates/consumer/__dot__claude/settings.json.tpl +++ b/tools/templates/consumer/__dot__claude/settings.json.tpl @@ -1,11 +1,11 @@ { "enableAllProjectMcpServers": false, "enabledMcpjsonServers": ["oss"], + "env": { + "CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD": "1" + }, "permissions": { - "deny": [ - "Edit(./node_modules/**)", - "Write(./node_modules/**)" - ], + "deny": ["Edit(./node_modules/**)"], "additionalDirectories": ["{{ossFromRoot}}"] }, "hooks": { diff --git a/tools/templates/consumer/__dot__rulesync/rules/oss-boundaries.md.tpl b/tools/templates/consumer/__dot__rulesync/rules/oss-boundaries.md.tpl index b6a35f25..12e1bb7b 100644 --- a/tools/templates/consumer/__dot__rulesync/rules/oss-boundaries.md.tpl +++ b/tools/templates/consumer/__dot__rulesync/rules/oss-boundaries.md.tpl @@ -23,7 +23,7 @@ description: OSS core is read-only except in an OSS worktree (paired changes); e When a fix can only live in core, change it in core - in a git worktree of `{{ossDir}}`, the one OSS path the hook lets you write. Works the same from any agent tool; `docs/agents/cross-repo.md` lists how each tool is granted access to `{{ossDir}}`. -**Scope.** In place means small: a core bug, a missing export or field, a contract this repo needs aligned. A new core feature, module, or anything that reshapes a domain goes to a session rooted in the OSS repo - use the `handoff` skill. +**Scope.** Any core change can be made here, in the worktree: a bug, a missing export or field, a contract alignment, or a new feature or module. Use the `handoff` skill only when the work should run in a separate session rooted in the OSS repo. **Genericity test - before the first edit.** Core serves every operator, and this session carries this operator's requirements. Write down, for the OSS PR's Why section: why it cannot be an overlay, adapter, or config here, and why another operator would want the same change. If only this operator needs it, core gets only the seam (an adapter token, an event, a config field, a hook) and the behavior stays in this repo. Jurisdiction rules, vendor specifics, and limits or flows only this operator uses never go into core. diff --git a/tools/templates/consumer/__dot__rulesync/skills/handoff/SKILL.md b/tools/templates/consumer/__dot__rulesync/skills/handoff/SKILL.md index c507d807..1201bbdc 100644 --- a/tools/templates/consumer/__dot__rulesync/skills/handoff/SKILL.md +++ b/tools/templates/consumer/__dot__rulesync/skills/handoff/SKILL.md @@ -29,10 +29,10 @@ disallowed-tools: Turn "what we're doing" into a prompt a _stranger_ agent can act on with zero access to this chat. The receiver has none of our context, so the prompt must carry all of it. -Common use here: an OSS-core change too large, or too unrelated to this repo's diff, to make in -place. A small paired change is made here, in an OSS worktree - see "Changing OSS core" in the -`oss-boundaries` rule. Otherwise the receiver is a teammate or a new agent session rooted in the -platform checkout, and either way it needs a standalone brief. +Common use here: an OSS-core change that should run in a separate session. Any paired change can +be made here, in an OSS worktree - see "Changing OSS core" in the `oss-boundaries` rule. When it +runs elsewhere, the receiver is a teammate or a new agent session rooted in the platform +checkout, and either way it needs a standalone brief. Optional argument = what to hand off / who to (e.g. `the OSS core publish fix`, `to a teammate in the platform repo`, a repo path, an issue/MR#). No argument -> hand off the current in-flight task. diff --git a/tools/templates/consumer/__dot__rulesync/skills/review/SKILL.md.tpl b/tools/templates/consumer/__dot__rulesync/skills/review/SKILL.md.tpl index 3a6d8ad1..c4f8f1e4 100644 --- a/tools/templates/consumer/__dot__rulesync/skills/review/SKILL.md.tpl +++ b/tools/templates/consumer/__dot__rulesync/skills/review/SKILL.md.tpl @@ -91,7 +91,6 @@ No match: write `no paired OSS change` in the report and move on. - Every export, route, event payload, config field, or table the OSS diff changes: `git grep -w` it in this repo and confirm each use still compiles and still means the same thing. A consumer caller that no longer holds is a `[BLOCK]`. - Every consumer change that relies on the OSS change (a new export, a changed signature or behavior) is matched in the OSS diff. Consumer code relying on OSS behavior the diff does not ship is a `[BLOCK]`. - Genericity: OSS code that encodes this operator's behavior - a jurisdiction rule, a vendor, a limit or flow only this repo needs - instead of a seam (adapter token, event, config field, hook) is a `[BLOCK]`; the behavior moves here and core keeps the seam. An OSS PR whose Why does not say why the change cannot live in the consumer is a `[WARN]`. -- Scope: a new core feature or module made in place, rather than in a session rooted in the OSS repo, is a `[WARN]` citing the `oss-boundaries` rule. - Public record: operator names, internal URLs, ticket text, or operator-specific domain detail in the OSS commits or PR is a `[BLOCK]`. - Release order: a consumer request that needs the OSS change can merge only once the `@openora/*` pin points at a canary that carries it. Say so in the report when the pin is older. - When a trace needs runtime proof: `pnpm oss:worktree --link`, run the touched tests, then `pnpm link:oss` to restore the main checkout link. diff --git a/tools/templates/consumer/docs/agents/cross-repo.md.tpl b/tools/templates/consumer/docs/agents/cross-repo.md.tpl index df4f1d19..58c37b8d 100644 --- a/tools/templates/consumer/docs/agents/cross-repo.md.tpl +++ b/tools/templates/consumer/docs/agents/cross-repo.md.tpl @@ -6,7 +6,7 @@ Some changes need both repos: an OSS core change plus this repo's adaptation to - **OSS code is changed only in a worktree**: `pnpm oss:worktree ` creates or reuses `{{ossDir}}/.worktrees/` and installs its dependencies. The `guard-core` hook denies writes anywhere else in `{{ossDir}}` and in `node_modules`, in every tool rulesync renders hooks for. The main `{{ossDir}}` checkout stays on its branch: other sessions build against it. - **Core gets generic changes only**: before touching core, state why it cannot live here and why another operator would want it. Operator-specific behavior stays here; core gets only the seam. -- **In place means small**: bug fixes, missing exports, contract alignment. New core features go to a session rooted in the OSS repo (`handoff` skill). +- **Any core change can be made here**, new features included, in the worktree. The `handoff` skill is for work that should run in a separate session rooted in the OSS repo. - **Review before push**: `pnpm -C verify`, then the OSS repo's own review workflow and its contract checklist on the worktree diff. - **Same branch name in both repos** pairs the two requests. Skills find the OSS half from this repo's branch. - **No links between the requests**: the shared branch name is the pairing. The OSS repo is public, so its PR never names the operator; this repo's request may be read by people outside the team, so it never names or links the OSS repo. @@ -16,11 +16,20 @@ Some changes need both repos: an OSS core change plus this repo's adaptation to The full procedure lives in "Changing OSS core" in the `oss-boundaries` rule. +## Example asks + +One session covers both halves; start it here with `{{ossDir}}` added (see below). + +- "{{trackerKey}}-123: the withdrawal list needs a `currency` filter. Add it to the OSS contract in a worktree, then use it here." +- "The OSS bug behind {{trackerKey}}-456: fix it in a worktree, link it, and rerun this repo's e2e against it." +- "Review this branch and its OSS pair." +- "Both requests merged: bump `@openora/*` and remove the worktree." + ## Giving each tool access to `{{ossDir}}` Grant the whole `{{ossDir}}`, not only `.worktrees/`: a worktree keeps its git metadata in `{{ossDir}}/.git`, so committing there writes to it. The hook still limits file edits to the worktree. -- **Claude Code**: `permissions.additionalDirectories: ["{{ossDir}}"]` in `.claude/settings.json`, checked in. Takes effect once the workspace is trusted. Per session: `--add-dir {{ossDir}}` or `/add-dir`. +- **Claude Code**: `permissions.additionalDirectories: ["{{ossDir}}"]` in `.claude/settings.json`, checked in. Takes effect once the workspace is trusted. That grants file access only; `claude --add-dir {{ossDir}}` (or `/add-dir {{ossDir}}`) also loads the OSS repo's skills and agents, and with `CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1` in the `env` block of `.claude/settings.json`, checked in, its `CLAUDE.md` and `.claude/rules/`. - **Codex CLI**: `codex --add-dir {{ossDir}}`. `.codex/config.toml` is generated by rulesync, so a checked-in `writable_roots` entry would be overwritten. A personal alternative is `[sandbox_workspace_write] writable_roots` in `~/.codex/config.toml` with an absolute path. - **GitHub Copilot CLI**: `copilot --add-dir {{ossDir}}`, or `/add-dir {{ossDir}}` in the session. No project-level key exists. - **Gemini CLI**: `gemini --include-directories {{ossDir}}`, or `/directory add {{ossDir}}`. `.gemini/settings.json` is generated by rulesync.