Skip to content

Commit c417e18

Browse files
authored
feat(skills): add setup-override-upstream — promote local override into framework PR (#43)
New framework skill that walks an adopter through promoting a local `.apache-steward-overrides/<skill>.md` file into a PR against `apache/airflow-steward`. Closes the loop on the override mechanism: overrides start out as adopter-local modifications (per #38 + #39), and when one stops being project-specific and starts looking like a missing feature, this skill is the path to upstream it. Walkthrough Step 0 — Pre-flight (adopter has overrides + snapshot is current + framework clone available) Step 1 — Pick the override (auto-pick when only one; prompt when multiple) Step 2 — Read the override + the framework skill it modifies Step 3 — Decide if upstreamable. Four buckets: - project-specific → STOP (keep as override) - missing feature → continue - better default → continue - refactor a step → continue Step 4 — Design the framework-level abstraction. Four possible shapes (config knob / change default / new optional step / refactor existing step) Step 5 — Implement in user's apache-steward clone, run framework pre-commit Step 6 — Confirm + open PR (assistant proposes, user fires) Step 7 — Surface post-merge cleanup pointer (after merge + /setup-steward upgrade, delete the override file) Golden rules 1. Not every override should be upstreamed. 2. Write to the framework clone, never to the gitignored snapshot. 3. Assistant proposes, user fires (clone, branch, commit, push, PR — every state-changing action confirmed first). 4. Decouple PR open from override deletion (the cleanup happens AFTER the PR merges, not preemptively). Includes the standard pre-flight blocks per the framework's conventions: - ## Adopter overrides — consults .apache-steward-overrides/setup-override-upstream.md (per #39). - ## Snapshot drift — compares local lock vs committed lock (per #41), with a doubly-important note: the skill designs against the snapshot's framework code, so stale snapshot leads to wrong abstraction design. Generated-by: Claude Code (Claude Opus 4.7)
1 parent 71ea36e commit c417e18

1 file changed

Lines changed: 360 additions & 0 deletions

File tree

  • .claude/skills/setup-override-upstream
Lines changed: 360 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,360 @@
1+
---
2+
name: setup-override-upstream
3+
description: |
4+
Walk an adopter through promoting a local
5+
`.apache-steward-overrides/<skill>.md` file into a PR
6+
against `apache/airflow-steward`. Lists the adopter's
7+
overrides, helps the user pick one, reads it alongside the
8+
framework skill it modifies, helps decide whether the
9+
change is generalisable (some overrides encode project-
10+
specific decisions and should stay local), designs the
11+
framework-level abstraction (configurable parameter,
12+
optional step, changed default, etc.), implements it in
13+
the user's local apache-steward clone, runs the
14+
framework's pre-commit, and opens the PR. After the PR
15+
merges and the adopter runs `/setup-steward upgrade`, the
16+
override file in the adopter repo is no longer needed and
17+
the skill prompts for its removal.
18+
when_to_use: |
19+
Invoke when the user says "upstream my override", "promote
20+
this override to the framework", "convert my local
21+
modification into a steward feature", "make this override
22+
a framework feature", "open a PR to apache-steward for
23+
this override", or similar — typically after running the
24+
override locally for a while and deciding the change is
25+
worth contributing back.
26+
license: Apache-2.0
27+
---
28+
29+
<!-- SPDX-License-Identifier: Apache-2.0
30+
https://www.apache.org/legal/release-policy.html -->
31+
32+
<!-- Placeholder convention (see ../../AGENTS.md#placeholder-convention-used-in-skill-files):
33+
<adopter-repo> → repo this skill is being run in (an adopter)
34+
<override-file> → .apache-steward-overrides/<skill>.md being upstreamed
35+
<framework-skill> → framework skill the override modifies
36+
<framework-clone> → user's local clone of apache/airflow-steward
37+
(separate from .apache-steward/, which is a gitignored snapshot)
38+
<framework-fork> → user's GitHub fork of apache/airflow-steward
39+
(where the PR branch gets pushed) -->
40+
41+
# setup-override-upstream
42+
43+
This skill is the path from *local override* to *framework
44+
feature*. It takes a single
45+
`.apache-steward-overrides/<skill>.md` file in an adopter
46+
repo, walks the user through deciding whether the change is
47+
worth upstreaming, designs the framework-level abstraction,
48+
implements it in `apache/airflow-steward`, and opens a PR.
49+
50+
The override mechanism (per
51+
[`docs/setup/agentic-overrides.md`](../../../docs/setup/agentic-overrides.md))
52+
is deliberately *agentic* and *adopter-local*: there's no
53+
schema, no anchors, no patch tool. That makes overrides
54+
quick to write but hard to share — every adopter who wants
55+
the same behaviour writes their own. **Upstreaming** is the
56+
escape hatch: when an override stops being project-specific
57+
and starts looking like a missing feature, the right move
58+
is a PR that bakes the change into the framework's default,
59+
making every adopter benefit on their next
60+
`/setup-steward upgrade`.
61+
62+
## Adopter overrides
63+
64+
Before running the default behaviour documented below, this
65+
skill consults
66+
[`.apache-steward-overrides/setup-override-upstream.md`](../../../docs/setup/agentic-overrides.md)
67+
in the adopter repo if it exists, and applies any
68+
agent-readable overrides it finds. See
69+
[`docs/setup/agentic-overrides.md`](../../../docs/setup/agentic-overrides.md)
70+
for the contract — what overrides may contain, hard rules,
71+
the reconciliation flow on framework upgrade, upstreaming
72+
guidance.
73+
74+
**Hard rule**: agents NEVER modify the snapshot under
75+
`<adopter-repo>/.apache-steward/`. Local modifications go in
76+
the override file. Framework changes go via PR to
77+
`apache/airflow-steward`.
78+
79+
---
80+
81+
## Snapshot drift
82+
83+
Also at the top of every run, this skill compares the
84+
gitignored `.apache-steward.local.lock` (per-machine
85+
fetch) against the committed `.apache-steward.lock` (the
86+
project pin). On mismatch the skill surfaces the gap and
87+
proposes
88+
[`/setup-steward upgrade`](../setup-steward/upgrade.md).
89+
The proposal is non-blocking — the user may defer if
90+
they want to run with the local snapshot for now. See
91+
[`docs/setup/install-recipes.md` § Subsequent runs and drift detection](../../../docs/setup/install-recipes.md#subsequent-runs-and-drift-detection)
92+
for the full flow.
93+
94+
Drift severity:
95+
96+
- **method or URL differ** → ✗ full re-install needed.
97+
- **ref differs** (project bumped tag, or `git-branch`
98+
local is behind upstream tip) → ⚠ sync needed.
99+
- **`svn-zip` SHA-512 mismatches the committed
100+
anchor** → ✗ security-flagged; investigate before
101+
upgrading.
102+
103+
> **Doubly important here**: the skill is about to design
104+
> a framework-level abstraction by reading the snapshot's
105+
> framework skill. If the snapshot is stale, the
106+
> abstraction may be designed against a version that has
107+
> already changed upstream. Address drift before
108+
> proceeding.
109+
110+
---
111+
112+
## Golden rules
113+
114+
**Golden rule 1 — not every override should be upstreamed.**
115+
Many overrides encode genuinely *project-specific* choices:
116+
the wording of a canned response, the project's scope-label
117+
taxonomy, milestone-format regex, a tone-of-voice
118+
preference. These should stay in the adopter repo. The
119+
skill explicitly walks through this decision and stops
120+
early if the change is not generalisable.
121+
122+
**Golden rule 2 — write to `<framework-clone>`, never to
123+
the snapshot.** The framework PR is implemented in the
124+
user's local apache-steward clone (a separate working
125+
directory from the adopter's `.apache-steward/` snapshot,
126+
which is gitignored and read-only). If the user does not
127+
have a clone yet, the skill helps them set one up.
128+
129+
**Golden rule 3 — assistant proposes, user fires.** Per the
130+
framework convention (see
131+
[`AGENTS.md`](../../../AGENTS.md)), every state-changing
132+
action — clone, branch, commit, push, `gh pr create` — is
133+
proposed by the skill and only happens on explicit user
134+
confirmation. Public PR content is shown to the user before
135+
it is posted.
136+
137+
**Golden rule 4 — decouple PR from override deletion.**
138+
Opening the framework PR is one step; deleting the now-
139+
redundant override file in the adopter repo is a separate
140+
step that happens AFTER the PR has merged AND the adopter
141+
has run `/setup-steward upgrade` to pick up the framework
142+
change. The skill ends with a clear pointer at the
143+
post-merge cleanup; it does not delete the override
144+
preemptively.
145+
146+
## Walk-through
147+
148+
### Step 0 — Pre-flight
149+
150+
1. We are in an adopter repo (has
151+
`<adopter-repo>/.apache-steward.lock` and
152+
`<adopter-repo>/.apache-steward-overrides/`). If not,
153+
stop — the skill is for adopters with at least one
154+
override file.
155+
2. The snapshot is current (no drift per the section
156+
above). If drift exists, propose
157+
`/setup-steward upgrade` first.
158+
3. Identify `<framework-clone>` — the user's local clone
159+
of `apache/airflow-steward`. Common locations:
160+
`~/code/airflow-steward/`, `~/work/airflow-steward/`.
161+
If not found, surface and ask the user where it is, or
162+
help them clone it (`git clone
163+
git@github.com:apache/airflow-steward.git`). The clone
164+
is **separate** from `<adopter-repo>/.apache-steward/`
165+
(the snapshot).
166+
167+
### Step 1 — Pick the override
168+
169+
List `<adopter-repo>/.apache-steward-overrides/*.md`
170+
(excluding the directory's own `README.md`). For each,
171+
print the file name + first headline.
172+
173+
- **Zero overrides** → stop. There is nothing to upstream.
174+
- **One override** → auto-pick.
175+
- **Multiple** → ask the user which one to upstream this
176+
run. The skill handles one override per invocation
177+
(clean PR, clean review).
178+
179+
### Step 2 — Read the override + framework skill
180+
181+
Read the chosen override file. Surface to the user:
182+
183+
- Title + the override headlines (`### Override N — ...`)
184+
- The "why" paragraph if the file has one
185+
186+
Then read the framework skill it modifies, from the
187+
snapshot at
188+
`<adopter-repo>/.apache-steward/.claude/skills/<framework-skill>/`.
189+
Surface:
190+
191+
- The skill's purpose (frontmatter description)
192+
- The specific section(s) the override modifies (steps,
193+
decision-table rows, golden rules)
194+
- Any cross-skill references the override depends on
195+
196+
Goal: both the user and the agent should now have a clear
197+
mental model of *what* the change is and *where* it
198+
applies.
199+
200+
### Step 3 — Decide if upstreamable
201+
202+
Walk through with the user. Common categories:
203+
204+
- **Project-specific** (canned-response wording, scope
205+
labels, milestone formats, tooling assumptions
206+
particular to this project) → **stop here**. Suggest the
207+
override stay local. Generalising would require the
208+
framework to either include the adopter's specifics
209+
(defeats project-agnosticism) or expose a config knob
210+
that no other adopter would set the same way (bloats the
211+
contract).
212+
- **Missing feature** (the override does something useful
213+
that any adopter might want) → **continue**. The
214+
framework should learn this behaviour by default, or
215+
expose it as an opt-in.
216+
- **Better default** (the override changes a default the
217+
framework currently picks; if a majority of adopters
218+
would prefer the override's default, the framework
219+
should adopt it) → **continue**. The PR may also keep
220+
the old behaviour reachable via a flag.
221+
- **Refactor a step** (the framework's step is
222+
awkward / redundant / has an edge case) → **continue**.
223+
The PR fixes the step itself.
224+
225+
If the user is unsure, lean toward **stop** — keep the
226+
override local until a second adopter wants the same thing.
227+
228+
### Step 4 — Design the framework-level abstraction
229+
230+
Once the user confirms the change is upstreamable, design
231+
the framework-side change. Pick one of:
232+
233+
| Shape | When |
234+
|---|---|
235+
| **Add a config knob** in `<project-config>/` | The change is opt-in per-adopter; default behaviour is unchanged. |
236+
| **Change a default** | The new behaviour is better for the majority; the framework's existing default becomes a `<project-config>/` opt-out. |
237+
| **Add an optional step** | The change is an *additional* step (not a substitute for an existing one). |
238+
| **Refactor existing step** | The change rewrites how an existing step works. No new config; the new behaviour is universal. |
239+
240+
Surface the proposal to the user. Iterate. The output of
241+
this step is a concrete plan: which framework files to
242+
modify, what to add / remove / change, what tests or
243+
verification the framework already has that may need
244+
updating.
245+
246+
### Step 5 — Implement in the framework clone
247+
248+
In `<framework-clone>`:
249+
250+
1. `git fetch origin && git checkout -b
251+
feat/<short-description> origin/main`
252+
2. Apply the changes the design step decided on. Read the
253+
surrounding framework code first (the framework's
254+
`AGENTS.md`, the relevant supporting files of the
255+
modified skill) to match conventions.
256+
3. Run framework pre-commit:
257+
`prek run --all-files`. Fix anything that fires.
258+
4. Show the user the diff (`git diff`). Get explicit
259+
confirmation before committing.
260+
5. Commit with a message matching the framework's
261+
conventions (Conventional-Commits prefix:
262+
`feat(skills): ...` for new framework behaviour,
263+
`refactor(skills): ...` for restructure, etc.). Use
264+
`Generated-by: Claude Code (Claude Opus 4.7)` trailer
265+
per the framework's no-coauthored-by hook.
266+
267+
### Step 6 — Open the PR
268+
269+
1. `git push -u <fork-remote> feat/<branch>`. If no fork
270+
remote is configured, surface and help the user add one
271+
(`git remote add fork <user>/airflow-steward.git`).
272+
2. Draft the PR title + body. Include:
273+
- **Summary** — what the change is, in 1–3 bullets.
274+
- **Motivation** — link to the originating override
275+
file in the adopter repo (the user's project), with
276+
enough context that the framework reviewer
277+
understands the use case without reading the full
278+
override.
279+
- **Migration path for existing adopters** — if the
280+
change introduces a new config knob, explain the
281+
default; if it changes a default, explain how
282+
adopters opt out.
283+
- **Test plan** — what the user verified locally.
284+
3. **Confirm with the user before posting**. Show the
285+
exact title + body. Wait for "OK to post" / "yes" /
286+
"send" / similar before running `gh pr create`.
287+
4. `gh pr create --repo apache/airflow-steward --base
288+
main --head <user>:<branch> --title "..." --body "..."`
289+
290+
### Step 7 — Post-PR cleanup pointer
291+
292+
After the PR is open, surface to the user:
293+
294+
```text
295+
Framework PR opened: <PR URL>
296+
297+
Next steps once it merges:
298+
299+
1. /setup-steward upgrade (in <adopter-repo>)
300+
- Bumps the snapshot to the new framework version.
301+
- .apache-steward.lock will reflect the new pin.
302+
2. Delete .apache-steward-overrides/<skill>.md in <adopter-repo>
303+
- The override is now redundant; the framework does
304+
what the override used to do.
305+
3. Commit the deletion + the bumped lock together.
306+
```
307+
308+
The skill **does not** delete the override file itself —
309+
that happens after the PR merges, and the skill cannot
310+
predict when (or if) the framework reviewers accept the
311+
PR. Deletion is the user's manual cleanup once the PR
312+
lands.
313+
314+
## Output to the user (skill end)
315+
316+
```text
317+
✓ Override picked: .apache-steward-overrides/<skill>.md
318+
✓ Framework skill: <framework-skill>
319+
✓ Decision: upstreamable as <shape from Step 4>
320+
✓ Framework clone: <framework-clone>
321+
✓ Branch: feat/<short-description>
322+
✓ Commits: <count>
323+
✓ PR opened: <PR URL>
324+
325+
Next: wait for the PR to merge, then in <adopter-repo>:
326+
/setup-steward upgrade
327+
rm .apache-steward-overrides/<skill>.md
328+
git add -A && git commit -m "Remove override <skill>: upstreamed in apache/airflow-steward#<N>"
329+
```
330+
331+
## Failure modes
332+
333+
| Symptom | Likely cause | Remediation |
334+
|---|---|---|
335+
| `<adopter-repo>` has no `.apache-steward-overrides/` | not adopted, or adopted without the overrides scaffold | run `/setup-steward adopt` (idempotent) |
336+
| Step 1 finds zero overrides | nothing to upstream — adopter has no local modifications recorded | stop |
337+
| `<framework-clone>` not found | user has not cloned `apache/airflow-steward` yet | help them clone, then resume |
338+
| Framework pre-commit fails after the implementation | the change does not match framework conventions | iterate with the user, re-run pre-commit, do not bypass with `--no-verify` |
339+
| User decides mid-flow that the override is project-specific after all | wrong call in Step 3 | stop without opening a PR; the override file in the adopter repo is unchanged, no harm done |
340+
341+
## What this skill is NOT for
342+
343+
- Not for *applying* an override at run-time — that is the
344+
per-skill pre-flight protocol documented in
345+
[`docs/setup/agentic-overrides.md`](../../../docs/setup/agentic-overrides.md).
346+
- Not for *creating* a new override — that is
347+
[`/setup-steward override <skill>`](../setup-steward/overrides.md).
348+
- Not for *upgrading* the snapshot — that is
349+
[`/setup-steward upgrade`](../setup-steward/upgrade.md).
350+
Run that BEFORE this skill if drift exists.
351+
- Not for arbitrary framework PRs unrelated to overrides.
352+
This skill is specifically the override → PR flow. Other
353+
framework contributions (new skill, new tool, refactor)
354+
go through the framework's normal PR workflow.
355+
356+
## Cross-references
357+
358+
- [`docs/setup/agentic-overrides.md`](../../../docs/setup/agentic-overrides.md) — the override contract.
359+
- [`setup-steward/overrides.md`](../setup-steward/overrides.md) — how to *create* / *open* an override.
360+
- [`setup-steward/upgrade.md`](../setup-steward/upgrade.md) — how to upgrade the snapshot post-merge.

0 commit comments

Comments
 (0)