Framework Contribute
Open a pull request that carries a local framework improvement back to that framework's repo. Each governance
framework is pinned as a git submodule — a real clone with its own remote — so the change already lives in a
working tree that can branch and PR directly. There is no temp-clone and no file-copy (that machinery only exists
in the single-upstream template-copy model).
This skill is identity-decoupled: it works for any contributor against any framework repo. The maintainer of
a repo and an outside contributor to it are equal first-class cases — the skill probes the actual permission at
runtime and takes the matching path. Nothing about who owns which repo is written into this file.
Model (read first)
- The change is already in the submodule's working tree (the user edited the framework in place). Contribution =
branch + commit + push + PR — on whichever remote the contributor can push to.
- Everything identity-bearing is resolved at runtime, never hardcoded (skill_spec §9, identity dimension):
- target repo + upstream →
git -C <path> remote get-url origin (parse <owner>/<repo> from it).
- the contributor's identity →
gh api user --jq .login (whoever is logged in).
- write access → probed live:
gh api repos/<owner>/<repo> --jq .permissions.push (true/false decides the path).
No org, account, or repo name is baked in. The skill is correct across org migrations and for external contributors
without edits.
Prerequisites — GitHub CLI (gh)
- Verify:
gh auth status.
- Install: Windows
winget install GitHub.cli · Linux sudo apt install gh / brew install gh · macOS brew install gh.
- Post-install:
gh auth login.
Pre-Check (Step 0, mandatory)
- Detect
gh. Not found → show the install command for the detected OS, ask, stop.
gh auth status. Not authenticated → gh auth login, ask, stop.
- Identify the target submodule (user names the framework, or infer from the dirty submodule). Resolve its path,
parse
<owner>/<repo> from git remote get-url origin, read the logged-in user (gh api user).
- Probe permission (this selects the path, not configuration):
gh api repos/<owner>/<repo> --jq .permissions.push.
true → Path A · direct branch (push a contrib branch to the repo, in-repo PR).
false → Path B · fork (fork, push to the fork, cross-repo PR).
Both paths produce the same artifact — a PR against the framework's default branch. They are peers; neither is a
downgrade.
Trigger (manual only)
User invokes when they want a local framework change upstreamed.
- Keywords: "贡献框架" / "contribute framework" / "推框架改动" / "framework PR" / "回贡献上游".
Shared steps (both paths)
Step 1 — Identify the change
- In the target submodule:
git -C <path> status + git -C <path> diff against origin/<default-branch>.
- If the submodule is at a detached HEAD on the pinned tag (the normal pinned state), the working-tree edits sit on
top of that tag. Establish a proper branch base before committing — never commit on a detached HEAD:
git -C <path> fetch origin
git -C <path> checkout -b contrib/<task-id>-<short-summary> origin/<default-branch> (base on upstream head, then
re-apply the edits) — or branch from current HEAD and rebase onto origin/<default-branch> if the exact tree must
be preserved.
- If there are no changes vs upstream → "No framework changes to contribute" → end.
Step 2 — Present & confirm
- Show the diff summary (files + hunks) and the resolved target (
<owner>/<repo>:<default-branch>) and which path the
permission probe selected. Ask the user to confirm scope.
Step 3 — CHANGELOG + VERSION (framework release discipline)
- Draft a
## [Unreleased] CHANGELOG entry (or suggest the next semver per the framework's
Framework_Release.procedure — patch/minor/major). Show for edit. The maintainer may finalize the version at merge.
Step 4 — Commit (both paths)
README check (mandatory, before opening the PR)
- If the change affects a capability the framework's
README.md describes (new rule, skill, workflow, trigger),
update both README.md + README_zh.md in the same contrib branch (the framework's R29+ entry-doc freshness
obligation in readme-style.md, incl. R30 README-freshness).
Path A · contributor with push access
A5. Push the branch to the repo's own origin: git -C <path> push origin contrib/<task-id>-<short-summary>.
A6. Open the PR in-repo: gh pr create --repo <owner>/<repo> --base <default-branch> --head contrib/<task-id>-<short-summary>.
A7. Restore the pinned state: after the PR is open, return the submodule to its pinned tag so the consuming
project's gitlink stays consistent — git -C <path> checkout <pinned-tag> (the branch remains on origin for the
PR). Do not advance the consuming gitlink to the contrib branch (the pin only moves later via syncing-frameworks on
the consumer's version gate, after merge + release).
Path B · contributor without push access (fork)
B5. Fork: gh repo fork <owner>/<repo> --clone=false; detect the fork owner (gh api user --jq .login).
B6. Add the fork as a remote and push: git -C <path> remote add fork <fork-url> (temporary), then
git -C <path> push fork contrib/<task-id>-<short-summary>.
B7. Open the cross-repo PR: gh pr create --repo <owner>/<repo> --base <default-branch> --head <fork-owner>:contrib/<task-id>-<short-summary>.
B8. Cleanup: remove the temporary fork remote (git -C <path> remote remove fork) and restore the pinned state
as in A7.
Step 7 (both paths) — Output
- Print the PR URL. Note: "Maintainer reviews + merges on GitHub; a consumer's pin moves later via
syncing-frameworks on
its own version gate." Mirror the event into the consuming project's flow_log.md.
PR body (both paths)
## Source
- Project: <project_id>
- Based on: <pinned-tag/commit>
## Changes
<file list with one-line summaries>
## Changelog Entry
<drafted changelog text>
## Contributor
<name> (<email>)
Important notes
- Always a PR, never a direct merge; the PR targets the framework's own default branch.
- Only the framework's own files are contributed — instance files and consuming-project runtime ledgers are never
pushed upstream.
- Contributor
Co-Authored-By is mandatory.
- No identity is hardcoded: owner/repo come from the remote, the contributor from
gh api user, the path from a
live permission probe. The maintainer path (A) and the external-contributor path (B) are equal first-class cases.
- Difference from the single-upstream reference: no temp-clone, no file-copy —
the change is already in the submodule clone; we branch + PR it in place. The fork path is preserved as a peer for
contributors without write access, not as a fallback.
1---2name: contributing-framework-changes3description: Contribute a local improvement to a governance framework back to that framework's repo via a pull request. Use when a local framework or skill-home change should be proposed upstream. Works for any contributor — write-access holders push a branch to the repo directly; contributors without write access fork and open a cross-repo PR. The path is chosen at runtime by probing the actual permission; no identity, org, or account is hardcoded.4---56# Framework Contribute78Open a pull request that carries a local framework improvement back to that framework's repo. Each governance9framework is pinned as a **git submodule** — a real clone with its own remote — so the change already lives in a10working tree that can branch and PR directly. **There is no temp-clone and no file-copy** (that machinery only exists11in the single-upstream template-copy model).1213This skill is **identity-decoupled**: it works for *any* contributor against *any* framework repo. The maintainer of14a repo and an outside contributor to it are **equal first-class cases** — the skill probes the actual permission at15runtime and takes the matching path. Nothing about who owns which repo is written into this file.1617## Model (read first)18- The change is already in the submodule's working tree (the user edited the framework in place). Contribution =19 branch + commit + push + PR — on whichever remote the contributor can push to.20- **Everything identity-bearing is resolved at runtime, never hardcoded** (skill_spec §9, identity dimension):21 - target repo + upstream → `git -C <path> remote get-url origin` (parse `<owner>/<repo>` from it).22 - the contributor's identity → `gh api user --jq .login` (whoever is logged in).23 - **write access → probed live**: `gh api repos/<owner>/<repo> --jq .permissions.push` (true/false decides the path).24 No org, account, or repo name is baked in. The skill is correct across org migrations and for external contributors25 without edits.2627## Prerequisites — GitHub CLI (`gh`)28- **Verify**: `gh auth status`.29- **Install**: Windows `winget install GitHub.cli` · Linux `sudo apt install gh` / `brew install gh` · macOS `brew install gh`.30- **Post-install**: `gh auth login`.3132### Pre-Check (Step 0, mandatory)331. Detect `gh`. Not found → show the install command for the detected OS, ask, **stop**.342. `gh auth status`. Not authenticated → `gh auth login`, ask, **stop**.353. Identify the target submodule (user names the framework, or infer from the dirty submodule). Resolve its path,36 parse `<owner>/<repo>` from `git remote get-url origin`, read the logged-in user (`gh api user`).374. **Probe permission** (this selects the path, not configuration):38 `gh api repos/<owner>/<repo> --jq .permissions.push`.39 - `true` → **Path A · direct branch** (push a contrib branch to the repo, in-repo PR).40 - `false` → **Path B · fork** (fork, push to the fork, cross-repo PR).41 Both paths produce the same artifact — a PR against the framework's default branch. They are peers; neither is a42 downgrade.4344## Trigger (manual only)45User invokes when they want a local framework change upstreamed.46- **Keywords**: "贡献框架" / "contribute framework" / "推框架改动" / "framework PR" / "回贡献上游".4748## Shared steps (both paths)49### Step 1 — Identify the change50- In the target submodule: `git -C <path> status` + `git -C <path> diff` against `origin/<default-branch>`.51- If the submodule is at a **detached HEAD on the pinned tag** (the normal pinned state), the working-tree edits sit on52 top of that tag. **Establish a proper branch base before committing** — never commit on a detached HEAD:53 - `git -C <path> fetch origin`54 - `git -C <path> checkout -b contrib/<task-id>-<short-summary> origin/<default-branch>` (base on upstream head, then55 re-apply the edits) — or branch from current HEAD and rebase onto `origin/<default-branch>` if the exact tree must56 be preserved.57- If there are no changes vs upstream → "No framework changes to contribute" → **end**.5859### Step 2 — Present & confirm60- Show the diff summary (files + hunks) and the resolved target (`<owner>/<repo>:<default-branch>`) and which path the61 permission probe selected. Ask the user to confirm scope.6263### Step 3 — CHANGELOG + VERSION (framework release discipline)64- Draft a `## [Unreleased]` CHANGELOG entry (or suggest the next semver per the framework's65 `Framework_Release.procedure` — patch/minor/major). Show for edit. The maintainer may finalize the version at merge.6667### Step 4 — Commit (both paths)68- On the `contrib/<task-id>-<short-summary>` branch. Commit with the contributor's own identity69 (`git config user.name` / `user.email`):70 ```71 <short summary>7273 Contributed from <project_id>. Based on <pinned-tag/commit>.7475 Co-Authored-By: <name> <email>76 ```7778### README check (mandatory, before opening the PR)79- If the change affects a capability the framework's `README.md` describes (new rule, skill, workflow, trigger),80 update both `README.md` + `README_zh.md` in the same contrib branch (the framework's R29+ entry-doc freshness81 obligation in `readme-style.md`, incl. R30 README-freshness).8283## Path A · contributor with push access84A5. **Push the branch to the repo's own origin**: `git -C <path> push origin contrib/<task-id>-<short-summary>`.85A6. **Open the PR in-repo**: `gh pr create --repo <owner>/<repo> --base <default-branch>86 --head contrib/<task-id>-<short-summary>`.87A7. **Restore the pinned state**: after the PR is open, return the submodule to its pinned tag so the consuming88 project's gitlink stays consistent — `git -C <path> checkout <pinned-tag>` (the branch remains on origin for the89 PR). Do not advance the consuming gitlink to the contrib branch (the pin only moves later via `syncing-frameworks` on90 the consumer's version gate, after merge + release).9192## Path B · contributor without push access (fork)93B5. **Fork**: `gh repo fork <owner>/<repo> --clone=false`; detect the fork owner (`gh api user --jq .login`).94B6. **Add the fork as a remote and push**: `git -C <path> remote add fork <fork-url>` (temporary), then95 `git -C <path> push fork contrib/<task-id>-<short-summary>`.96B7. **Open the cross-repo PR**: `gh pr create --repo <owner>/<repo> --base <default-branch>97 --head <fork-owner>:contrib/<task-id>-<short-summary>`.98B8. **Cleanup**: remove the temporary `fork` remote (`git -C <path> remote remove fork`) and restore the pinned state99 as in A7.100101## Step 7 (both paths) — Output102- Print the PR URL. Note: "Maintainer reviews + merges on GitHub; a consumer's pin moves later via `syncing-frameworks` on103 its own version gate." Mirror the event into the consuming project's `flow_log.md`.104105## PR body (both paths)106```107## Source108- Project: <project_id>109- Based on: <pinned-tag/commit>110111## Changes112<file list with one-line summaries>113114## Changelog Entry115<drafted changelog text>116117## Contributor118<name> (<email>)119```120121## Important notes122- Always a **PR**, never a direct merge; the PR targets the framework's own default branch.123- Only the **framework's own** files are contributed — instance files and consuming-project runtime ledgers are never124 pushed upstream.125- Contributor `Co-Authored-By` is mandatory.126- **No identity is hardcoded**: owner/repo come from the remote, the contributor from `gh api user`, the path from a127 live permission probe. The maintainer path (A) and the external-contributor path (B) are **equal first-class cases**.128- **Difference from the single-upstream reference**: no temp-clone, no file-copy —129 the change is already in the submodule clone; we branch + PR it in place. The fork path is preserved as a peer for130 contributors without write access, not as a fallback.