From 616bdf3e0b82a99abeb5a6e14f9f2c3f45158855 Mon Sep 17 00:00:00 2001 From: Jarek Potiuk Date: Sun, 3 May 2026 19:19:04 +0200 Subject: [PATCH] =?UTF-8?q?feat(skills):=20add=20setup-steward=20=E2=80=94?= =?UTF-8?q?=20snapshot+overrides=20adoption=20mechanism?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the submodule-based adoption design with snapshot + agentic overrides. One skill (setup-steward) lives committed in the adopter repo; everything else flows from it. The setup-steward skill (multi-file) .claude/skills/setup-steward/ ├── SKILL.md entry point + sub-action dispatch + golden rules ├── adopt.md first-time install — detect convention, │ download snapshot, gitignore, symlinks, │ .apache-steward-overrides/ scaffold, │ post-checkout hook, project-doc note ├── upgrade.md refresh snapshot + reconcile overrides ├── verify.md read-only health check ├── conventions.md skills-dir convention auto-detection │ (flat vs double-symlinked) └── overrides.md interactive override scaffolder Sub-actions /setup-steward — first-time adoption (default) /setup-steward upgrade — refresh the gitignored snapshot /setup-steward verify — health check /setup-steward override — open / scaffold an override Replaces (folded into setup-steward as sub-actions) - setup-steward-upgrade → /setup-steward upgrade (snapshot mechanics, not git pull) - setup-steward-verify → /setup-steward verify Adoption mechanism - The framework lives at /.apache-steward/ as a gitignored --depth=1 git checkout (or, once official ASF releases ship per https://www.apache.org/legal/release-policy.html, a signed tarball from the canonical ASF dist mirrors per https://infra.apache.org/release-distribution.html). - Framework skills are accessed via gitignored symlinks in the adopter's existing skill directory, matching whichever convention the adopter uses (flat or double-symlinked). - Adopter modifications to framework workflows live as agent-readable markdown under .apache-steward-overrides/, committed in the adopter repo. The framework's skills consult those files at run-time and apply the overrides before executing default behaviour. Hard rule: agents NEVER modify the snapshot — local mods go to overrides; framework changes go via PR to apache/airflow-steward. Agentic-override design contract New top-level docs/setup/agentic-overrides.md captures: - where override files live and what they may contain - how a framework skill consults overrides at run-time - hard rules on what the framework agent will never do - reconciliation flow on framework upgrade - upstreaming an override (PR against the framework) - why agentic, not declarative (variance trade-off accepted in exchange for restructure-survival + free-form expression) README rewrite Top-level README is reshaped around the new adoption flow: - "How adoption works" (snapshot + overrides in 3 bullets) - "Adopting the framework" (`tell your agent: 'adopt apache/airflow-steward in my repo'` + the 3-step agentic flow that follows) - The rename heads-up + candidate-name list (kept from #37) - Skill-family overview (setup / security / pr-management) - Maintenance commands Generated-by: Claude Code (Claude Opus 4.7) --- .claude/skills/setup-steward-upgrade/SKILL.md | 215 --------------- .claude/skills/setup-steward-verify/SKILL.md | 246 ----------------- .claude/skills/setup-steward/SKILL.md | 197 ++++++++++++++ .claude/skills/setup-steward/adopt.md | 243 +++++++++++++++++ .claude/skills/setup-steward/conventions.md | 105 ++++++++ .claude/skills/setup-steward/overrides.md | 136 ++++++++++ .claude/skills/setup-steward/upgrade.md | 148 +++++++++++ .claude/skills/setup-steward/verify.md | 143 ++++++++++ README.md | 179 +++++++------ docs/setup/agentic-overrides.md | 248 ++++++++++++++++++ 10 files changed, 1313 insertions(+), 547 deletions(-) delete mode 100644 .claude/skills/setup-steward-upgrade/SKILL.md delete mode 100644 .claude/skills/setup-steward-verify/SKILL.md create mode 100644 .claude/skills/setup-steward/SKILL.md create mode 100644 .claude/skills/setup-steward/adopt.md create mode 100644 .claude/skills/setup-steward/conventions.md create mode 100644 .claude/skills/setup-steward/overrides.md create mode 100644 .claude/skills/setup-steward/upgrade.md create mode 100644 .claude/skills/setup-steward/verify.md create mode 100644 docs/setup/agentic-overrides.md diff --git a/.claude/skills/setup-steward-upgrade/SKILL.md b/.claude/skills/setup-steward-upgrade/SKILL.md deleted file mode 100644 index a2f575a9..00000000 --- a/.claude/skills/setup-steward-upgrade/SKILL.md +++ /dev/null @@ -1,215 +0,0 @@ ---- -name: setup-steward-upgrade -description: | - Pull the user's local `airflow-steward` framework checkout to the - latest `origin/main` and surface what changed — the commits - pulled, the files touched (with focus on the secure-setup blast - radius: `.claude/settings.json`, `tools/agent-isolation/`, - `docs/setup/secure-agent-setup.md`, `docs/setup/secure-agent-internals.md`, - `pinned-versions.toml`), and the next-step recommendation. Never - applies user-side propagation itself — that is the job of - `setup-isolated-setup-update` (drift report) and the framework - maintainer's manual re-`cp` of any user-scope script copies that - drifted. Refuses to act if the working tree is dirty or the - branch has unpushed commits, since both states are signs the - user has work in flight that a `git pull` could clobber. -when_to_use: | - Invoke when the user says "upgrade apache-steward", "pull the - framework to latest", "bring my airflow-steward clone up to - date", or after Claude Code surfaces something new from the - framework's release notes. Also appropriate as the entry point - to a periodic update routine — recommended cadence per - docs/setup/secure-agent-setup.md is once per Claude Code upgrade or once - a month, whichever comes first; this skill is the *first* step - of that routine, with `setup-isolated-setup-update` (read-only drift - report) and any subsequent re-`cp` / `/setup-shared-config-sync` runs - following on. Do **not** invoke when the user has uncommitted - changes in the framework checkout or when they have local - commits ahead of origin — the skill will refuse and surface - the state. ---- - - - -# setup-steward-upgrade - -This skill is the **upstream** half of the framework's update flow. -It moves the user's local `airflow-steward` checkout forward to -`origin/main` and reports what arrived. The downstream half — what -this upgrade means for the user's *installed* secure setup -(user-scope script copies, project `.claude/settings.json`, pinned -tool versions on the host) — is the -[`setup-isolated-setup-update`](../setup-isolated-setup-update/SKILL.md) skill, -which is read-only and runs naturally as the next step. - -## Golden rules - -- **Refuse on a dirty working tree.** If `git status --short` in - the framework checkout reports any modified, staged, or - conflicted files, surface them and stop. A `git pull` on top of - uncommitted edits is one of the quickest ways to lose work; the - user is in flight on something and needs to commit / stash it - themselves before any pull. Do not auto-stash. -- **Refuse on local commits ahead of `origin/main`.** Adopters - generally consume `airflow-steward` as a read-only checkout — - modifications happen via PRs that land on `main` upstream, then - the user's checkout is `git pull`ed. If the user has commits - ahead of `origin/main`, that is either (a) work in progress for - a PR they have not pushed, or (b) a local fork they are - maintaining. Both cases need explicit user direction; the skill - does not assume. -- **`--ff-only` only.** Use `git pull --ff-only`. Never - `--rebase`, never a merge commit. The skill is for the simple - case where the user's checkout is strictly behind upstream; - anything else is the user's call. If the fast-forward fails - (history diverged), surface and stop. -- **Show what arrived.** After a successful pull, surface the - commit list and a per-file change summary, with explicit focus - on the secure-setup blast radius (`.claude/settings.json`, - `tools/agent-isolation/`, `docs/setup/secure-agent-setup.md`, - `docs/setup/secure-agent-internals.md`, - `tools/agent-isolation/pinned-versions.toml`). The user should - walk away knowing whether this upgrade has user-side - follow-through to do. -- **Do not propagate to user-scope.** This skill ends at the - framework checkout. It does not re-`cp` `claude-iso.sh`, - `sandbox-bypass-warn.sh`, or `sandbox-status-line.sh` into - `~/.claude/`. It does not edit any project's - `.claude/settings.json`. It does not bump installed tool - versions on the host. All of those are surfaced by the - follow-on `setup-isolated-setup-update` skill, which is read-only by - design — the user decides what to apply. - -## Walk-through - -1. **Locate the framework checkout.** Confirm with the user the - path to their local `airflow-steward` clone. If they don't - have one, surface that and stop — they need to `git clone` - first. - -2. **Pre-flight checks.** - - `git -C status --short` — must be empty. If not, list - the modified files and stop. - - `git -C rev-parse --abbrev-ref HEAD` — must be `main` - (or the local equivalent that tracks `origin/main`). If not, - name the branch and stop; the user is on a feature branch - and a pull would be the wrong action. - - `git -C rev-list --count @{u}..HEAD` — must be `0`. - If not, surface the local commits and stop. - -3. **Fetch + diff against upstream.** - - `git -C fetch origin` (always, even if behind). - - `git -C rev-list --count HEAD..@{u}` — if `0`, the - checkout is already up to date; report and stop. - - Otherwise, list the commits that will land: - `git -C log --oneline HEAD..@{u}`. - - List per-file changes with secure-setup focus: - `git -C diff --name-status HEAD..@{u}` — call out - entries under `.claude/settings.json`, - `tools/agent-isolation/**`, `docs/setup/secure-agent-setup.md`, - `docs/setup/secure-agent-internals.md`, `pinned-versions.toml` if they - appear. - -4. **Confirm with the user before pulling.** Show the commits - and the file-touch summary, then ask for explicit OK. The - skill does not auto-pull on a "looks routine" judgement — - even a doc-only upgrade can move anchors that the user's - bookmarks or scripts depend on. - -5. **Pull.** `git -C pull --ff-only`. If the fast-forward - fails for any reason, surface the error and stop. - -6. **Post-pull report.** Confirm the new HEAD SHA matches - `origin/main`. Re-print the commit list (now landed) and the - file-touch summary with the secure-setup focus. - -7. **Hand off to follow-up actions.** Always finish by naming - the next-step skills the user is likely to want, with explicit - conditions: - - - **If the framework checkout is a submodule of an adopter - tracker repo** (the path is - `/.apache-steward/apache-steward/`), remind - the user that **the parent tracker now has a stale submodule - pointer**. Pulling the framework standalone moved the - framework's `HEAD`, but the parent tracker's index still - records the previous SHA. The user has two options: (a) - commit the new pointer in the parent tracker - (`git -C add .apache-steward/apache-steward && git - commit -m "Bump apache-steward submodule"`), or (b) revert - the framework checkout to the SHA the parent tracker pins. - Option (a) is the usual path. Either way, a follow-up - `git -C submodule update --init --recursive` on - any other clone of the tracker is what makes that clone see - the new framework. Mention the post-merge hook documented in - `README.md → Adopting the framework` for users who want this - automatic. Suggest - [`setup-steward-verify`](../setup-steward-verify/SKILL.md) - to confirm the parent tracker's submodule integration is - still aligned (the skill catches the `+` "submodule HEAD - ahead of parent index" state directly). - - - **Always after a successful pull**, recommend - [`setup-isolated-setup-update`](../setup-isolated-setup-update/SKILL.md) - to surface user-side drift the upgrade may have introduced - (new `permissions.deny` patterns the user's tracker repo - hasn't picked up, drift between user-scope `~/.claude/` - copies and the just-updated framework source-of-truth, a - pinned-tool version bump that warrants a host-side - `npm install` / `apt-get install`). - - - **If `tools/agent-isolation/*.sh` files changed in the - pulled commits AND the user maintains a `~/.claude-config` - sync repo with copies of those scripts**, recommend - re-`cp`'ing the updated framework scripts over the - `~/.claude-config/scripts/` (or - `~/.claude/agent-isolation/`) copies and then running - [`setup-shared-config-sync`](../setup-shared-config-sync/SKILL.md) to - push the propagated changes to the sync remote so other - machines pick them up. - - - **If `pinned-versions.toml` changed**, name the specific - tool(s) bumped and remind the user that the host install - commands in `docs/setup/secure-agent-setup.md → Required tools` may - now reference newer versions; the user runs the `apt-get` - / `dnf` / `npm install` themselves (the skill does not - touch system tools). - - - **If `.claude/settings.json` changed**, name the kinds of - changes (new `denyRead`, new `allowedDomains`, new - `permissions.ask` entry) and remind the user that adopter - tracker repos copying the framework's settings will need a - manual merge — the skill does not auto-merge into adopter - repos. - -## What this skill is NOT for - -- Not for upgrading a tracker repo (the user's own private - repo where they consume the framework). Tracker-repo updates - are normal `git pull` operations the user does themselves. -- Not for upgrading installed tools (`bubblewrap`, `socat`, - `claude-code`). Those bumps happen on the host via the - package manager, surfaced by `check-tool-updates.sh` and - approved per the - [Bumping a pinned version](../../../docs/setup/secure-agent-setup.md#bumping-a-pinned-version) - flow. -- Not for syncing user-scope edits to `~/.claude-config`. That - is `setup-shared-config-sync`'s job. - -## Failure modes - -- **Working tree dirty.** Stop. Surface `git status` output. The - user commits / stashes themselves before re-invoking. -- **Local commits ahead of upstream.** Stop. Surface the commit - list. The user pushes their PR / decides what to do, then - re-invokes. -- **Not on `main` (or tracking branch).** Stop. Surface the - current branch. The user switches branches themselves. -- **`fetch` fails.** Network or auth issue. Stop and surface. - The skill does not retry. -- **`pull --ff-only` fails (diverged history).** This means - someone force-pushed `main` upstream, or the user's local - `main` has untracked commits. Stop and surface. The user - resolves themselves; the skill never `--force`-pulls or - resets. diff --git a/.claude/skills/setup-steward-verify/SKILL.md b/.claude/skills/setup-steward-verify/SKILL.md deleted file mode 100644 index b0d36107..00000000 --- a/.claude/skills/setup-steward-verify/SKILL.md +++ /dev/null @@ -1,246 +0,0 @@ ---- -name: setup-steward-verify -description: | - Verify that the `apache-steward` framework is correctly integrated - into the user's adopter tracker repository — `.apache-steward/` - directory at the tracker root, the framework checked out as a git - submodule under `.apache-steward/apache-steward/`, the submodule - initialised and pointer-aligned with the parent tracker's index, - the adopter's `` (the `.apache-steward/` - directory itself) populated with no remaining `TODO:` - placeholders for required fields, and the optional post-merge - hook wired up. Reports ✓ done / ✗ missing / ⚠ partial for each - check with concrete remediation commands. Read-only — never - modifies the tracker, the submodule, or ``. -when_to_use: | - Invoke when the user says "verify apache-steward setup", "is - the framework integrated correctly?", "check tracker setup", - "did the submodule init?", or after bootstrapping a new - adopter tracker per the - [Adopting the framework](../../../README.md#adopting-the-framework) - section. Also appropriate after a fresh `git clone` of a - pre-configured tracker (the `.apache-steward/` is in the index - but the submodule needs `--init`), and after a tracker - contributor reports skills are stale or missing — the most - common cause is a parent `git pull` that bumped the submodule - pointer without a follow-up `git submodule update`. Do **not** - invoke from inside the framework checkout itself; the skill - detects that and reports it as a misuse. ---- - - - -# setup-steward-verify - -This skill is the **integration check** for adopters who consume -the `apache-steward` framework as a git submodule of their -tracker repo (the canonical pattern, documented in -[`README.md` → Adopting the framework](../../../README.md#adopting-the-framework)). -It confirms the framework is wired in correctly so the rest of -the framework's skills and tools resolve from the right paths. - -The companion skill is -[`setup-isolated-setup-verify`](../setup-isolated-setup-verify/SKILL.md), which -verifies the *secure-agent setup* (sandbox, hooks, status line, -clean-env wrapper). The two are independent: an adopter can have -the framework correctly integrated as a submodule but no secure -setup wired (setup-isolated-setup-verify catches that), or have the -secure setup wired against a stale / un-init'd framework -submodule (this skill catches that). Run both for a complete -adopter-side health check. - -## Golden rules - -- **Read-only.** This skill never runs `git submodule update`, - never edits `/project.md`, never wires the - post-merge hook, never resets the submodule. If a check - fails, surface the gap and the remediation command for the - user to run; do not auto-fix. -- **Always run every check, even on early failure.** A missing - `.apache-steward/` directory is ✗ at check 2 — but checks - 3, 4, 5 (project-config, gitmodules, submodule init) are - still useful in their own right and might surface a - separate problem (e.g. partial bootstrap that left - `.apache-steward/project.md` filled but the submodule never - added). Report every check; do not stop at the first ✗. -- **Refuse from inside the framework checkout.** If the cwd - resolves to the framework repo itself - (`apache/airflow-steward` per the `origin` remote, or a - worktree of it), surface that and stop — this skill is for - tracker repos that *consume* the framework, not for - the framework itself. Suggest `cd ` and re-invoke. -- **Distinguish ✗ from ⚠.** ✗ is a structural integration - failure (skills cannot resolve, framework path is broken, - submodule pointer drift). ⚠ is an *intentional or - recoverable* variant (the post-merge hook is optional; - some `TODO:` placeholders in `project.md` are for fields - the adopter has not yet decided about, like which mailing - list to subscribe to). Use ⚠ for "should be done eventually - but the framework still works"; ✗ for "skills will fail - silently or surface stale data". - -## Pre-flight: where am I? - -Before running checks, resolve the cwd: - -1. `git rev-parse --show-toplevel` — the current repo root. -2. Check `git remote get-url origin` — if it resolves to - `apache/airflow-steward` (or any direct fork of the - framework), this skill is being invoked from inside the - framework. Surface and stop. -3. If `/.apache-steward/` does not exist, the user - may be either (a) in a tracker that does not yet integrate - the framework, or (b) in some other repo entirely. Surface - the cwd, name what is missing, and stop with the bootstrap - pointer. - -Otherwise, the cwd is a tracker that integrates the framework — -proceed with the checks. - -## The checks - -### 1. `.apache-steward/` directory present - -`/.apache-steward/` exists and is a directory. - -- ✗ if missing — the framework is not integrated. Remediation: - follow - [Adopting the framework](../../../README.md#adopting-the-framework) - to copy `projects/_template/` into `/.apache-steward/` - and add the framework as a submodule under it. - -### 2. `/project.md` present and required fields filled - -`/.apache-steward/project.md` exists. - -Then `grep -nE '^TODO:|: TODO:|^\| TODO:|`grep`-able TODO marker'` -inside `project.md` to enumerate unfilled fields. Distinguish: - -- ✗ for unfilled fields the framework relies on at runtime — - `tracker_repo:`, `upstream_repo:`, `tracker_default_branch:` - in the `## Repositories` block; the issue-template scope - labels in `## Issue-template fields`. The skills will fail - to resolve placeholders without these. -- ⚠ for unfilled fields that are convenience-only or apply - only to optional flows — mailing-list addresses (only the - import / sync skills need them), CVE tooling URLs (only - the security-cve-allocate skill), Gmail / PonyMail OAuth flags - (only the email-using skills). - -Print the unfilled-field list with line numbers so the user -can grep + edit. - -### 3. `.gitmodules` has the framework entry - -`/.gitmodules` exists and has a `[submodule -".apache-steward/apache-steward"]` block with `path = -.apache-steward/apache-steward` and a `url =` pointing at the -upstream framework. Accept either -`https://github.com/apache/airflow-steward.git` (or `.git` -suffix omitted) or any direct ssh-style equivalent -(`git@github.com:apache/airflow-steward.git`); the canonical -remote is `apache/airflow-steward` until the future rename to -`apache/steward`, at which point this skill will accept either. - -- ✗ if `.gitmodules` missing or the entry is missing — - remediation: run `git submodule add` per the README's - bootstrap, or add the entry by hand if the user is mid-merge. -- ⚠ if `url =` points at a fork (not directly at - `apache/airflow-steward` / `apache/steward`) — that is - legitimate when an adopter is testing a framework PR locally, - but flag it so the user notices. - -### 4. Submodule initialised + working tree present - -`/.apache-steward/apache-steward/.git` exists (it -is normally a `.git` *file* pointing into -`/.git/modules/.apache-steward/apache-steward/`, not a -directory — both shapes are valid). - -`ls /.apache-steward/apache-steward/` should -list non-empty: at least `README.md`, `AGENTS.md`, -`.claude/skills/`, `tools/`. If those files are missing, the -submodule has been added in the parent's index but never -checked out. - -- ✗ if the submodule directory exists but contains no files - (the most common state after a fresh `git clone` of the - tracker) — remediation: - `git submodule update --init --recursive` from the tracker - root. -- ✗ if the framework's expected top-level files are absent — - the submodule is checked out at an unexpected commit; - remediation: investigate, then either commit the new - pointer in the parent or reset to the recorded SHA. - -### 5. Submodule pointer aligned with parent's index - -`git -C submodule status .apache-steward/apache-steward` -output. The leading character classifies the state: - -- a single space prefix = aligned, ✓. -- `+` prefix = the submodule's `HEAD` is *ahead of* the SHA - recorded in the parent's index. The user has either pulled - the framework directly without committing the new pointer - in the parent (`setup-steward-upgrade` skill mentions this - case), or has hand-checked-out a different SHA. Surface as - ⚠ — the framework still works, but the parent will record - a different pointer on the next commit. Remediation: commit - the new pointer in the parent, or reset the submodule to - the recorded SHA (`git -C - .apache-steward/apache-steward checkout `). -- `-` prefix = the submodule is *not initialised* (caught - earlier in check 4 — should not appear here if 4 already - ran). -- `U` prefix = merge conflict in the submodule. ✗ — surface - and stop; the user resolves manually. - -### 6. Post-merge hook wired - -`/.git/hooks/post-merge` exists, is executable, -and contains the `git submodule update --init --recursive` -recipe. - -- ⚠ if missing — strictly optional, but the adopter-facing - README recommends it because plain `git pull` on the - tracker only advances the submodule pointer in the index, - not the working tree, and a stale submodule means skills - silently run against a previous version of the framework. - Print the one-line install recipe from the README. - -## After the report - -If every check is ✓, say so explicitly and stop — no further -action needed. - -If anything is ✗ or ⚠, the report ends with a concrete next- -step list, ordered most → least urgent: - -- ✗ on checks 1 / 3 / 4 → run the bootstrap or - `git submodule update --init --recursive` per the README. - These block the rest of the framework's skills. -- ✗ on check 2 (required fields unfilled) → name the specific - fields and the line numbers in `/project.md` - the user must fill. These cause the framework's skills to - fail when they try to resolve `` / `` / - similar placeholders. -- ✗ on check 5 (`U` prefix, merge conflict) → resolve the - submodule conflict; the user owns this, the skill cannot - decide. -- ⚠ on check 5 (`+` prefix, pointer ahead) → name the - remediation choice (commit the new pointer in the parent, - or reset the submodule). The - [`setup-steward-upgrade`](../setup-steward-upgrade/SKILL.md) - skill is the natural place this state usually originates. -- ⚠ on check 6 (no post-merge hook) → print the install - recipe and tell the user this is optional ergonomics. -- ⚠ on check 2 (optional fields unfilled) → name the - fields, mention which skills they unlock, suggest filling - them when the user adopts those skills. - -Recommend -[`setup-isolated-setup-verify`](../setup-isolated-setup-verify/SKILL.md) as -the natural next-step skill if the user has not run it yet — -the two skills are independent but together cover the -adopter-side health check. diff --git a/.claude/skills/setup-steward/SKILL.md b/.claude/skills/setup-steward/SKILL.md new file mode 100644 index 00000000..12c59520 --- /dev/null +++ b/.claude/skills/setup-steward/SKILL.md @@ -0,0 +1,197 @@ +--- +name: setup-steward +description: | + Adopt and maintain the apache-steward framework in a project + repo using the snapshot-based adoption mechanism. The single + framework artefact that lives **committed** in an adopter's + repo — every other framework skill is a symlink into a + gitignored snapshot this skill manages. Sub-actions: + `/setup-steward` — first-time adoption (default) + `/setup-steward upgrade` — refresh the gitignored snapshot + `/setup-steward verify` — health check the integration + `/setup-steward override ` — open or scaffold an + agentic override for a framework + skill in `.apache-steward-overrides/` +when_to_use: | + Invoke when the user says "adopt apache-steward", "adopt + apache/airflow-steward", "set up steward in this repo", or + the agent equivalent triggered by following the framework's + README adoption instructions. Also for periodic maintenance: + "upgrade steward", "verify steward setup", "update the + steward snapshot". This is the only framework skill that + should be **copied** into an adopter's repo (every other + framework skill is a symlink the adopt sub-action wires up). +license: Apache-2.0 +--- + + + + + +# setup-steward + +This skill is **the only framework artefact an adopter +project commits**. Every other apache-steward skill (security, +pr-management) is a gitignored symlink into the gitignored +snapshot at `` that this skill manages. + +The adoption model is **snapshot + agentic overrides** (not +submodule, not marketplace, not vendored copy): + +- The framework is downloaded as a `--depth=1` git checkout (or, + once official ASF releases ship, a signed tarball) into + `` and **gitignored** in the adopter repo. The + snapshot is a build artefact, not source. +- Symlinks from the adopter's skill directory into + `/.claude/skills//` make the + framework's skills callable as if they lived in the adopter + repo. The symlinks are also **gitignored** because their + targets disappear on a fresh clone before `/setup-steward` + runs. +- Adopter-specific modifications to framework workflows live as + agent-readable instructions under + `.apache-steward-overrides/.md` (committed). They + invalidate or change steps the framework's skill would + otherwise run. See + [`overrides.md`](overrides.md) for the contract and + [`docs/setup/agentic-overrides.md`](../../../docs/setup/agentic-overrides.md) + for the design rationale. + +## Detail files in this directory + +| File | Purpose | +|---|---| +| [`adopt.md`](adopt.md) | First-time adoption walk-through — detect the adopter's skills-dir convention, download the snapshot, set up `.gitignore`, create the framework-skill symlinks, scaffold `.apache-steward-overrides/`, update the adopter's project docs. The default sub-action. | +| [`upgrade.md`](upgrade.md) | Refresh the gitignored snapshot to a newer framework version, reconcile any agentic overrides against the new framework structure, surface conflicts. | +| [`verify.md`](verify.md) | Read-only health check — snapshot present + intact, symlinks point at live targets, `.gitignore` correct, `.apache-steward-overrides/` exists, the `setup-steward` skill itself is current. | +| [`conventions.md`](conventions.md) | Adopter skills-dir convention auto-detection — flat `.claude/skills//`, the `.claude/skills/` → `.github/skills//` double-symlink pattern (e.g. apache/airflow), or neither yet. | +| [`overrides.md`](overrides.md) | Agentic-override file management — open / scaffold an override for a framework skill, list existing overrides, help reconcile when the framework changes the underlying skill's structure on upgrade. | + +## Golden rules + +**Golden rule 1 — never modify the snapshot.** The +`` is a build artefact, gitignored, and **read- +only** from an adopter's perspective. Every modification an +adopter wants must go into `.apache-steward-overrides/` (where +it is *committed* and survives the next `upgrade`). The skill, +and any other framework skill consulting overrides at run-time, +**never** writes to ``. If the user wants to +upstream a framework change, the agent reads the latest +`apache/airflow-steward` `main`, implements the change there, +and opens a PR against the framework repo. + +**Golden rule 2 — `.gitignore` keeps the adopter repo clean.** +Three things gitignored in the adopter repo: + +- `` (the entire framework snapshot) +- the symlinks `setup-steward adopt` creates in the adopter's + skills directory (they target the gitignored snapshot, so + they would dangle in a fresh clone) +- the adopter's own scratch artefacts that other framework + skills might create (`/tmp/...` style state caches) + +**Committed**: this skill (`setup-steward`), the +`.apache-steward-overrides/` directory, the `.gitignore` +entries themselves, any project-doc updates the `adopt` +sub-action makes. + +**Golden rule 3 — follow the adopter's existing skills-dir +convention.** Different ASF projects already organise their +`.claude/skills/` differently (see +[`conventions.md`](conventions.md)): + +- **flat**: `.claude/skills//SKILL.md` — directly in the + Claude Code-discovered location. +- **double-symlinked** (e.g. apache/airflow today): the actual skill + content lives under `.github/skills//` and + `.claude/skills/` is a symlink into it. Claude Code + discovers via `.claude/skills/`; the user maintains under + `.github/skills/`. + +The `adopt` sub-action detects which pattern is in place and +matches it. **The framework's symlinks land at the same depth +as the adopter's existing skills**, not one level off. + +**Golden rule 4 — copy this skill, symlink the rest.** This +skill (`setup-steward`) is the **only** framework skill that +gets copied into an adopter repo. All other framework skills +(`security-issue-import`, `pr-management-triage`, etc.) are +symlinked into the gitignored snapshot. Mixing the two — for +example, copying a security skill — creates a maintenance +hazard: copies drift from the framework's source-of-truth, and +agentic overrides (which assume the framework version is the +one in the snapshot) silently mis-apply. + +**Golden rule 5 — agentic overrides are read at run-time.** +Every framework skill that supports overrides starts its run +by checking `.apache-steward-overrides/.md` for +adopter-specific instructions and applying them before +executing the default behaviour. The override file is plain +markdown the agent interprets — no templating engine, no +patch tool. See +[`docs/setup/agentic-overrides.md`](../../../docs/setup/agentic-overrides.md) +for the contract. + +## Sub-actions + +The skill dispatches by the first positional argument: + +| Invocation | Loads | Purpose | +|---|---|---| +| `/setup-steward` (no args) | [`adopt.md`](adopt.md) | First-time adoption (default). | +| `/setup-steward adopt` | [`adopt.md`](adopt.md) | Same as no-arg — explicit form. | +| `/setup-steward upgrade` | [`upgrade.md`](upgrade.md) | Refresh snapshot + reconcile overrides. | +| `/setup-steward verify` | [`verify.md`](verify.md) | Read-only health check. | +| `/setup-steward override ` | [`overrides.md`](overrides.md) | Open / scaffold an override file. | + +If the snapshot is missing (no `/`), the skill +treats that as `adopt` regardless of which sub-action was +named — the user has invoked on a repo that has not yet been +adopted, and the right next step is to walk through adoption. + +## Inputs + +The skill is mostly driven by detection (it reads the adopter +repo's state) but accepts these optional flags: + +| Flag | Effect | +|---|---| +| `from:` | Adopt / upgrade from a specific framework `` (branch, tag, or commit SHA) instead of `main`. Useful for testing a framework PR locally before it merges. | +| `skill-families:` | Comma-separated list of skill families to symlink (`security`, `pr-management`). Default on adopt: prompt the user. Default on upgrade: re-symlink the families currently linked. | +| `dry-run` | Show what the skill would do without writing anything. | + +## What this skill is NOT for + +- Not for installing the secure agent setup (sandbox, hooks, + pinned tools). That is + [`setup-isolated-setup-install`](../setup-isolated-setup-install/SKILL.md). + The two are independent: an adopter can have steward set up + but no isolated-setup wired (run setup-isolated-setup-install + to fix), or have isolated-setup wired against a stale + snapshot (run `setup-steward upgrade`). +- Not for upgrading framework tools installed on the host + (`bubblewrap`, `socat`, `claude-code` itself). Those go via + [`setup-isolated-setup-update`](../setup-isolated-setup-update/SKILL.md). +- Not for syncing the user's `~/.claude-config` across + machines. That is + [`setup-shared-config-sync`](../setup-shared-config-sync/SKILL.md). +- Not for committing framework changes. Framework PRs go + against `apache/airflow-steward` directly — the snapshot is + read-only. + +## Failure modes + +| Symptom | Likely cause | Remediation | +|---|---|---| +| `/setup-steward verify` reports the snapshot present but the symlinks dangle | adopter ran a `git clone` but not `/setup-steward` after — symlinks are gitignored but persist in their target's absence | run `/setup-steward adopt` (it idempotently re-creates symlinks) | +| `/setup-steward upgrade` surfaces conflicts in `.apache-steward-overrides/.md` | the framework restructured the skill in a way that invalidates an existing override | open the override file, follow the conflict markers, or invoke `/setup-steward override ` to re-scaffold | +| Worktree off the adopter repo can't find framework skills | worktrees off the adopter don't auto-inherit the gitignored snapshot | the `adopt` sub-action installs a `post-checkout` git hook that re-runs the snapshot install on worktree creation; verify the hook is present (`/setup-steward verify`) | +| `git clone` of an upstream PR sees no framework skills | expected — the snapshot is gitignored, so a fresh clone has no ``. The clone needs `/setup-steward` once before any framework skill is invocable | run `/setup-steward` from the cloned repo | diff --git a/.claude/skills/setup-steward/adopt.md b/.claude/skills/setup-steward/adopt.md new file mode 100644 index 00000000..ddb5c24a --- /dev/null +++ b/.claude/skills/setup-steward/adopt.md @@ -0,0 +1,243 @@ + + +# adopt — first-time install of apache-steward into an adopter repo + +The default sub-action when the user says "adopt apache-steward". +Walks through detection, snapshot install, and the small set of +adopter-side artefacts that need to land on disk. + +## Inputs + +- `from:` — adopt from a specific framework `` + (default: `main` of `apache/airflow-steward`). +- `skill-families:` — comma-separated families to symlink + in (`security`, `pr-management`). Default: prompt the user. + +## Step 0 — Pre-flight + +1. Confirm we are in a git repo (`git rev-parse --show-toplevel`). + If not, surface and stop — the user opened the agent in the + wrong directory. +2. Confirm we are **not** in `apache/airflow-steward` itself + (read `git remote get-url origin` and refuse if it resolves + to the framework). Adopting the framework into itself is a + no-op the user did not intend. +3. Detect the adopter's existing skills-dir convention by + following [`conventions.md`](conventions.md). The result + pins which directory the framework symlinks land in + (`` from here on). + +## Step 1 — Pick the skill families + +If `skill-families:` was passed on the invocation, use those +verbatim. Otherwise, present the families to the user and let +them choose: + +- **`security`** — eight skills for security-issue handling + (`security-issue-import`, `security-issue-sync`, + `security-cve-allocate`, `security-issue-fix`, etc.). + Maintainer-only; not useful unless the project has a + security tracker. +- **`pr-management`** — three skills for maintainer-facing PR + queue work (`pr-management-triage`, + `pr-management-stats`, `pr-management-code-review`). +- **`setup`** *(implicit)* — the `setup-isolated-setup-*`, + `setup-steward-*`, `setup-shared-config-sync` skills. The + `setup` family is always installed because the snapshot + carries it; the symlinks are wired up regardless of the + user's other family picks. + +Show the user a short description of each family and ask which +to install. Default to whichever family the user named in +their initial "adopt" request (e.g. *"adopt apache-steward for +PR triage"* → `pr-management`). + +## Step 2 — Download the snapshot + +Place the snapshot at `/.apache-steward/`. Use the +WIP path for now (a `--depth=1` git checkout of the framework's +`main` branch). The signed-tarball path +(e.g. `https://downloads.apache.org/airflow/...` once ASF official +releases ship per +[release-policy](https://www.apache.org/legal/release-policy.html)) +is a future upgrade; both paths produce the same on-disk +shape. + +```bash +# WIP path — works today +git clone --depth=1 \ + --branch \ + https://github.com/apache/airflow-steward.git \ + .apache-steward +``` + +If `/.apache-steward/` already exists with content, +the user is in upgrade territory — refuse and suggest +`/setup-steward upgrade` instead. (Idempotent re-run after a +*partial* adopt is fine — see Step 6.) + +Pin the snapshot version into a small `.apache-steward.lock` +file at the repo root (committed) — record the source URL, +the resolved commit SHA, and the date. The `verify` and +`upgrade` sub-actions read this file. + +```text +# .apache-steward.lock (committed) +source: https://github.com/apache/airflow-steward.git +ref: main +commit: +fetched: +``` + +## Step 3 — `.gitignore` entries + +Add (if not already present) to `/.gitignore`: + +```text +# apache-steward — gitignored snapshot of the framework, refreshed +# by the setup-steward skill. The snapshot is a build artefact, not +# source. To re-create: /setup-steward (in your agent of choice). +/.apache-steward/ + +# Symlinks the setup-steward skill creates into the snapshot. They +# would dangle on a fresh clone before /setup-steward is run. +/.claude/skills/security-* +/.claude/skills/pr-management-* +/.claude/skills/setup-isolated-setup-* +/.claude/skills/setup-steward-* +/.claude/skills/setup-shared-config-sync +# ...mirror the same patterns under .github/skills/ if the adopter +# uses the double-symlinked convention (see conventions.md). +``` + +Show the diff to the user before writing. The `setup-steward` +skill itself (`*/setup-steward/`) is **not** gitignored — it +is committed. + +## Step 4 — Wire up the framework-skill symlinks + +For each skill family the user picked plus the `setup` family, +walk the snapshot's `.apache-steward/.claude/skills/` and create +a gitignored symlink for every matching skill at +`/` → relative path into +`.apache-steward/.claude/skills//`. + +If the adopter uses the double-symlinked convention +(`.claude/skills/` → `.github/skills//` per +[`conventions.md`](conventions.md)), create both layers — the +inner one in `.github/skills/` points at the snapshot, the +outer `.claude/skills/` points at the inner. + +**Never overwrite an existing committed skill** of the same name. +If the adopter repo already has e.g. `.github/skills/pr-triage` +(an old-name in-repo copy), surface the conflict and stop. The +user resolves manually — likely by deleting the stale copy and +re-running. + +Show the symlinks the skill is about to create, ask the user +to confirm, then create them. + +## Step 5 — Scaffold `.apache-steward-overrides/` + +Create `/.apache-steward-overrides/` (directory) if +it doesn't exist, with a small `README.md` inside that explains +the contract: + +```markdown +# apache-steward overrides + +Agent-readable instructions that **override** specific steps or +behaviours of the apache-steward framework's skills, scoped to +this adopter repo. Each override file is named after the +framework skill it modifies (e.g. `pr-management-triage.md` +overrides the `pr-management-triage` skill). + +The framework skills consult this directory at run-time before +executing default behaviour. See +[`docs/setup/agentic-overrides.md`](https://github.com/apache/airflow-steward/blob/main/docs/setup/agentic-overrides.md) +in the framework for the full contract. + +**Hard rule**: never modify the snapshot under +`/.apache-steward/`. Local mods go here. Framework +changes go via PR to `apache/airflow-steward`. +``` + +This directory is **committed** (the whole point is for +overrides to ship with the adopter repo). + +## Step 6 — Worktree-aware post-checkout hook + +Install a `post-checkout` git hook at +`/.git/hooks/post-checkout` that re-creates the +gitignored symlinks if a fresh worktree is checked out off +this repo. (The snapshot itself is gitignored and won't follow +the worktree, but the hook keeps the symlink shape consistent.) + +The hook is a one-liner that re-invokes +`/setup-steward verify --auto-fix-symlinks` against the new +worktree path. + +Surface the hook content to the user before writing. + +## Step 7 — Project doc updates + +Add (or extend) a brief paragraph in the adopter's `README.md` +or `CONTRIBUTING.md` (whichever already mentions agents / +skills) noting that this repo adopts apache-steward via the +snapshot mechanism, and pointing at: + +- [`apache-steward`'s top-level README](https://github.com/apache/airflow-steward) for the framework's overview; +- the local `.apache-steward-overrides/` for adopter-specific + modifications. + +Surface the doc diff to the user before writing. + +## Step 8 — Sanity check + +Run [`verify.md`](verify.md)'s checklist as a final step. Every +check should be ✓ before the skill reports success. + +## Output to the user + +A summary of what was written: + +```text +✓ Snapshot installed at .apache-steward/ (commit ) +✓ .gitignore updated (.apache-steward/, .claude/skills/security-*, ...) +✓ Symlinks created: + .claude/skills/security-issue-import → .apache-steward/.claude/skills/security-issue-import/ + .claude/skills/security-issue-sync → ... + ... +✓ .apache-steward-overrides/ scaffold created (committed) +✓ post-checkout hook installed +✓ README.md updated with adoption note + +Committed (you'll see in `git status`): + .gitignore + .apache-steward.lock + .apache-steward-overrides/README.md + .claude/skills/setup-steward/ (this skill itself) + README.md (or CONTRIBUTING.md) + +Gitignored (do NOT commit): + .apache-steward/ + .claude/skills/security-* + .claude/skills/pr-management-* (depending on family pick) + ... +``` + +Then suggest the user `git add` the committed files and open a +PR. + +## Failure modes + +- **Existing `/.apache-steward/`** → suggest + `/setup-steward upgrade`. +- **Existing committed skill conflicts with a framework skill + symlink** → stop, name the conflict, let the user resolve. +- **Network failure on the snapshot download** → stop, surface + the curl/git error. The user retries. +- **`.gitignore` already mentions `.apache-steward/` but no + snapshot is present** → either a partial adopt or a manual + cleanup. Re-run is safe; the skill detects this and proceeds. diff --git a/.claude/skills/setup-steward/conventions.md b/.claude/skills/setup-steward/conventions.md new file mode 100644 index 00000000..bbec436d --- /dev/null +++ b/.claude/skills/setup-steward/conventions.md @@ -0,0 +1,105 @@ + + +# conventions — auto-detect the adopter's skills-dir layout + +Different ASF projects already organise their `.claude/skills/` +differently. Before `setup-steward adopt` creates symlinks +into the snapshot, it detects which pattern is in place and +matches it. The framework's symlinks land at the same depth +as the adopter's existing skills, not one level off. + +## Patterns + +### A. Flat — skills live directly in `.claude/skills/` + +```text +/ +└── .claude/ + └── skills/ + └── / + └── SKILL.md +``` + +The simple, default Claude Code layout. Most repos that just +started using Claude Code use this. **Detection signal**: +`.claude/skills//SKILL.md` is a regular file. + +For framework symlinks: create them at +`/.claude/skills/` → relative path into +`.apache-steward/.claude/skills//`. + +### B. Double-symlinked — `.claude/skills/` mirrors `.github/skills/` + +```text +/ +├── .claude/ +│ └── skills/ +│ └── → ../../.github/skills// +└── .github/ + └── skills/ + └── / + └── SKILL.md +``` + +The pattern apache/airflow uses today (e.g. apache/airflow has this): actual skill content +lives under `.github/skills/`; `.claude/skills/` is a +relative symlink pointing into `.github/skills//`. The +rationale (per the airflow team): `.github/` is the canonical +infra-glue directory in apache/airflow (e.g. that project), and `.claude/` is a +view of those skills filtered for Claude Code. + +**Detection signal**: at least one entry in `.claude/skills/` +is a symlink resolving into `.github/skills/`. + +For framework symlinks: create *both* layers — the inner +`.github/skills/` → relative path into +`.apache-steward/.claude/skills//`, and the outer +`.claude/skills/` → `../../.github/skills//` (matching +the existing pattern). Both layers gitignored. + +### C. None yet — neither directory exists + +A new adopter that has never used Claude Code skills before. +The skill creates the directory layout the adopter prefers +(default: pattern A, flat — simpler). If the user has a +preference, they say so during the adopt flow. + +## Detection algorithm + +```text +if .claude/skills/ exists: + if any entry in .claude/skills/ is a symlink resolving + into .github/skills/: + pattern = B (double-symlinked) + else: + pattern = A (flat) +elif .github/skills/ exists: + pattern = B (the user has a `.github/skills/` half but + hasn't wired up `.claude/` yet — the adopt + flow will create the .claude/ side as part + of installing framework skills) +else: + pattern = C (none yet — default to A unless user picks + otherwise) +``` + +## What the adopt flow does per pattern + +| Pattern | `` (where framework symlinks land) | Side effect | +|---|---|---| +| A — flat | `.claude/skills/` | None | +| B — double-symlinked | `.github/skills/` (the inner layer); `.claude/skills/` symlinks to it | If `.github/skills/` for a framework skill already exists as a real directory (an old in-repo copy), refuse and let the user resolve | +| C — none yet | `.claude/skills/` | Create the directory | + +## Ambiguous cases + +- **The repo has both `.claude/skills/` and `.github/skills/` + but neither contains symlinks linking the two**. This is a + half-migrated state. The adopt flow surfaces it and asks + the user which pattern they want; it does not guess. +- **Pattern B but with absolute symlinks** (rather than + relative). The adopt flow will use *relative* symlinks for + consistency. If the user wants absolute, they say so; + otherwise relative is the default — it survives a repo + move. diff --git a/.claude/skills/setup-steward/overrides.md b/.claude/skills/setup-steward/overrides.md new file mode 100644 index 00000000..f52b4b7a --- /dev/null +++ b/.claude/skills/setup-steward/overrides.md @@ -0,0 +1,136 @@ + + +# overrides — manage agentic overrides for framework skills + +The agentic-overrides mechanism is the framework's answer to +"how does an adopter modify a framework skill's behaviour +without forking the framework". An override file lives at +`.apache-steward-overrides/.md` in the +adopter repo (committed). The framework skill consults the +file at run-time **before** executing default behaviour and +applies the agent-readable instructions in it. + +This sub-action helps the user manage those override files — +list them, scaffold a new one, or open an existing one. + +The full *contract* (what an override file may contain, how +the framework skill applies it, the hard rules that bound the +mechanism) lives in +[`docs/setup/agentic-overrides.md`](../../../docs/setup/agentic-overrides.md) +in the framework. This file is the operational helper. + +## Inputs + +- `` — required. The skill name to scaffold + / open the override for (e.g. `pr-management-triage`). + +## Step 0 — Pre-flight + +1. The repo must be adopted (see [`verify.md`](verify.md) + check 1 + check 5). If not, redirect to `/setup-steward + adopt`. +2. The named `` must exist in the snapshot at + `/.apache-steward/.claude/skills//`. + If not, name the typo and list the available framework + skills. + +## Step 1 — Resolve the override path + +`` = +`/.apache-steward-overrides/.md`. + +If `` already exists, this is an *open* +operation: surface the file's current content, ask the user +what they want to change, walk through the edit. Same as if +they had opened the file in their editor — the agent is just +doing it agentically. + +If `` doesn't exist, this is a *scaffold* +operation: continue to Step 2. + +## Step 2 — Scaffold a new override + +Read the framework skill's structure to know what the +override might target — the skill's section headings, golden +rules, decision-table rows, etc. Surface these as candidate +override anchors. + +Ask the user what they want to override: + +- *"Skip Step N"* → invalidate a specific step. +- *"Replace Step N with: ..."* → replace a step's behaviour. +- *"Add a new step before/after Step N: ..."* → insert. +- *"Always do X regardless of the framework's classification"* + → pre-empt the framework's decision logic. +- Free-form — the agent interprets at run-time. + +Generate the override file with the user's instructions. +Use the canonical scaffold below. + +## Override file scaffold + +```markdown + + + + +# Overrides for `` + +## Why these overrides exist + +(One paragraph explaining the local context. Why does this +adopter need to deviate from the framework's default? Future +maintainers — including the agent on a later run — read this +to know whether the override is still relevant.) + +## Overrides + +### Override 1 — + +(Free-form agent-readable instructions. The framework skill +applies these before running its default behaviour. Be +specific about which step / golden rule / decision-table row +the override targets.) + +### Override 2 — + +(...) +``` + +## Step 3 — Surface the contract reminders + +Whenever the skill scaffolds or opens an override file, +remind the user: + +1. **Never modify the snapshot** at + `/.apache-steward/`. Local mods go in this + override file. +2. **If the override is widely useful, upstream it.** Open a + PR against `apache/airflow-steward` implementing the change + in the framework skill itself. The framework will then + apply the change on every adopter's next + `/setup-steward upgrade`, and this adopter's override + becomes redundant — at which point the user deletes it. +3. **Re-anchor on framework upgrades.** The skill's + [`upgrade.md`](upgrade.md) sub-action surfaces conflicts + when a framework upgrade restructures a skill the user has + an override for. Re-anchor when prompted. + +## Failure modes + +- **Snapshot missing** → redirect to `/setup-steward upgrade`. +- **Skill name typo** → list available skills, ask again. +- **The override target is on a framework skill that does + not consult overrides** → the framework treats overrides + as opt-in per skill (each skill that supports overrides + documents this in its own `SKILL.md`). If the named + skill doesn't yet support overrides, surface that and + suggest opening a framework-side issue requesting the + hook. diff --git a/.claude/skills/setup-steward/upgrade.md b/.claude/skills/setup-steward/upgrade.md new file mode 100644 index 00000000..6434ed9e --- /dev/null +++ b/.claude/skills/setup-steward/upgrade.md @@ -0,0 +1,148 @@ + + +# upgrade — refresh the gitignored snapshot + reconcile overrides + +Refresh `/.apache-steward/` to a newer framework +version, surface what changed, and reconcile any agentic +overrides against the new framework structure. + +## Inputs + +- `from:` — bring the snapshot to a specific framework + ref (default: latest `main`). +- `dry-run` — show what would change without modifying anything. + +## Step 0 — Pre-flight + +1. Read `/.apache-steward.lock` for the current + pinned commit SHA. If missing, the repo isn't adopted — + suggest `/setup-steward adopt` and stop. +2. Read `/.apache-steward/` to confirm the snapshot + is on disk. If missing (gitignored, fresh clone), + re-download to the locked SHA first — that's the + recover-snapshot path, not an upgrade. Then continue. + +## Step 1 — Compare locked vs upstream + +Fetch upstream's latest SHA for the configured ref: + +```bash +git ls-remote https://github.com/apache/airflow-steward.git \ + refs/heads/main +``` + +If the locked SHA matches upstream, surface that and stop — +the snapshot is up to date. The user can re-invoke later. + +Otherwise, list the commits between locked and upstream +(shallow log via the GitHub API or by re-cloning into a temp +dir; both work). + +## Step 2 — Surface what changed + +Show the user: + +- The commit list (`git log --oneline ..`). +- Files touched in the framework `.claude/skills/` directory, + grouped by skill family. Call out any change to a skill the + adopter has an override for (overrides may need + reconciliation — see Step 4). +- Any change to the `setup-steward` skill itself in the + framework — that means the adopter's *committed* copy may + have drifted. Surface as an extra note; the adopter chooses + whether to re-copy. + +Ask for explicit confirmation before refreshing. + +## Step 3 — Refresh the snapshot + +Replace `/.apache-steward/` with a fresh +`--depth=1` clone at the new ref: + +```bash +rm -rf .apache-steward +git clone --depth=1 \ + --branch \ + https://github.com/apache/airflow-steward.git \ + .apache-steward +``` + +Update `.apache-steward.lock` with the new SHA + date. + +If the user is on a UNIX system with hardlink-aware tools, an +optimization is to clone alongside and `mv` — but a simple +nuke-and-clone is the canonical path and is what the skill +defaults to. The snapshot is gitignored anyway, so destroying +it loses no committed work. + +## Step 4 — Reconcile overrides + +For each file in `/.apache-steward-overrides/`: + +1. Check the corresponding framework skill exists in the new + snapshot. If not (skill renamed or removed), surface as a + conflict — the override may now apply to nothing. The user + either updates the override's target skill name or removes + the override. +2. If the framework skill's structure changed in a way the + override anchors against (e.g. the override invalidates + "Step 5 — Land the valid/invalid consensus" but the + framework renumbered or restructured steps), surface as a + conflict. The user re-anchors the override against the new + structure. + +The skill **does not** auto-rewrite overrides. It surfaces +conflicts and lets the user decide; agentic interpretation +means the right call is human judgement, not pattern-matching. + +## Step 5 — Re-create symlinks + +Walk `` looking for stale symlinks that +point at framework skills no longer in the new snapshot +(rename, removal). For each, ask the user to either: + +- Remove the stale symlink (renamed-away skill is gone), or +- Re-symlink to the new name (if the framework documented a + rename). + +Then walk the new snapshot for any new framework skills in +the families the adopter previously picked, and offer to +symlink them in. + +## Step 6 — Sanity check + +Run [`verify.md`](verify.md)'s checklist as a final step. + +## Output to the user + +```text +Snapshot refreshed: + X commits pulled (see list above) + Y framework skills changed + Z framework skills added + W framework skills renamed/removed (see Step 5) + +Overrides reconciled: + ✓ + ⚠ + +.apache-steward.lock updated. Symlinks refreshed. + +Recommended follow-ups: + - Run /setup-isolated-setup-update if the secure-setup blast + radius (settings.json, agent-isolation/, pinned-versions.toml) + appears in the diff. + - For each ⚠ override, open the file and re-anchor against the + new framework structure. +``` + +## Failure modes + +- **`.apache-steward.lock` missing** → repo not adopted yet; + suggest `/setup-steward adopt`. +- **Network failure** → stop, surface error, user retries. +- **Conflict during reconcile** → not a failure per se; the + skill surfaces the conflict and finishes the upgrade up to + the conflict. The user's next step is editing the override + files. diff --git a/.claude/skills/setup-steward/verify.md b/.claude/skills/setup-steward/verify.md new file mode 100644 index 00000000..3a12ec7e --- /dev/null +++ b/.claude/skills/setup-steward/verify.md @@ -0,0 +1,143 @@ + + +# verify — read-only health check of the steward integration + +Confirms the framework is wired in correctly so the rest of +the framework's skills resolve from the right paths. Read-only +— never modifies anything; surfaces gaps and remediation +commands. + +## Inputs + +- `--auto-fix-symlinks` — *exception to read-only*. If the + snapshot is present but symlinks are missing or dangling, + recreate them. Used by the post-checkout hook + ([`adopt.md` Step 6](adopt.md)) on a fresh worktree where + the gitignored symlinks didn't follow the checkout. + +## Pre-flight + +1. `git rev-parse --show-toplevel` — must succeed; we need a + repo root to resolve relative paths. +2. Read `git remote get-url origin`. If it resolves to + `apache/airflow-steward` (or a fork of), refuse — this + skill is for repos that *adopt* the framework, not for + the framework itself. +3. If `/.apache-steward.lock` is missing, the + repo is not adopted. Surface and stop with a pointer at + `/setup-steward adopt`. + +## The checks + +Run all checks even on early failure (a missing snapshot at +check 1 doesn't tell us anything about the override +directory or doc updates — surface every check). + +### 1. Snapshot present + intact + +`/.apache-steward/` exists, is a directory, and +contains the expected top-level files (`README.md`, +`AGENTS.md`, `.claude/skills/`, `tools/`). + +- ✗ if missing → run `/setup-steward upgrade` to re-fetch + (it gracefully handles the recover-snapshot case when the + lock file exists but the snapshot doesn't). +- ✗ if missing top-level files → snapshot is corrupted; same + remediation. + +### 2. Snapshot pinned to a real commit + +`/.apache-steward.lock` parses, the recorded +`commit:` SHA matches `git -C .apache-steward rev-parse HEAD`. + +- ⚠ if mismatch — somebody modified the snapshot manually. + Suggest `/setup-steward upgrade` to re-pin or `git -C + .apache-steward checkout ` to revert. + +### 3. `.gitignore` correctly excludes the snapshot + symlinks + +Check that the entries from +[`adopt.md` Step 3](adopt.md) are present in +`/.gitignore`. The snapshot path +`/.apache-steward/` is **required**; the symlink patterns are +**recommended** (otherwise a fresh clone may try to commit +dangling symlinks). + +- ✗ if `/.apache-steward/` is not gitignored — the snapshot + is at risk of being accidentally committed; remediation: + add the line. +- ⚠ if symlink patterns are not gitignored. + +### 4. Symlinks point at live framework skills + +For each symlink under `` that resolves +into `.apache-steward/.claude/skills//`: + +- ✓ if the target exists. +- ✗ if dangling (target deleted or snapshot missing). + Remediation: `/setup-steward adopt` (idempotent re-run) or + this same skill with `--auto-fix-symlinks`. + +For each framework skill in the snapshot that is **not** +symlinked in the adopter — surface as ⚠ with the family +classification (`security`, `pr-management`, `setup`). The +user may have intentionally not picked that family; the +warning prompts a decision. + +### 5. `.apache-steward-overrides/` exists + has the README + +`/.apache-steward-overrides/` is a directory with +the `README.md` scaffold from +[`adopt.md` Step 5](adopt.md). + +- ✗ if missing → `/setup-steward adopt` (idempotently + re-creates). +- ⚠ if present but `README.md` is missing — the directory + may have been hand-created. Suggest re-running + `/setup-steward adopt`. + +### 6. The `setup-steward` skill itself is up to date + +Compare the adopter-side committed `setup-steward` skill +against the snapshot's `.apache-steward/.claude/skills/setup-steward/`. + +- ✓ if same content. +- ⚠ if different — the adopter's committed copy has drifted. + Suggest re-copying from the snapshot. The user may have + intentional local tweaks; surface as ⚠ not ✗. + +### 7. Post-checkout hook installed + +`/.git/hooks/post-checkout` exists, is executable, +and contains the `setup-steward verify --auto-fix-symlinks` +recipe. + +- ⚠ if missing — strictly optional, but worktrees off this + repo will need a manual `/setup-steward verify + --auto-fix-symlinks` after checkout. Print the install + recipe. + +### 8. Project documentation mentions the framework + +`/README.md` (or another committed doc the +adopter picked) mentions the steward adoption with a link +into the framework. Cheap to skip if absent — surface as +⚠ only. + +## After the report + +If every check is ✓ (or ⚠ on items the adopter has +intentionally opted out of), say so explicitly and stop. + +If anything is ✗, end the report with a concrete next-step +list, ordered most → least urgent: + +- ✗ on check 1 → `/setup-steward upgrade` (re-fetches). +- ✗ on check 4 → `/setup-steward verify + --auto-fix-symlinks` (cheap; no-op when symlinks already + correct). +- ✗ on check 5 → `/setup-steward adopt` (idempotent + re-create). +- All other ✗ / ⚠ → name the gap, give the one-line + remediation. diff --git a/README.md b/README.md index 1c24eac2..bb34b290 100644 --- a/README.md +++ b/README.md @@ -3,15 +3,16 @@ **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* - [Apache Steward (to be renamed)](#apache-steward-to-be-renamed) - - [Skill families](#skill-families) + - [How adoption works](#how-adoption-works) - [Adopting the framework](#adopting-the-framework) - - [Keeping the submodule current](#keeping-the-submodule-current) + - [Skill families](#skill-families) + - [Maintenance](#maintenance) - [Cross-references](#cross-references) + https://www.apache.org/legal/release-policy.html --> # Apache Steward (to be renamed) @@ -46,98 +47,104 @@ > rename will only change the GitHub repository slug; existing > checkouts will keep working with a single `git remote set-url`. -Reusable, project-agnostic framework for ASF-project automation. -Adopters pull this repository into their own tracker as a git -submodule and ship project-specific configuration alongside it -under `/`. +A reusable, project-agnostic framework for ASF-project automation. +Currently in development for ASF projects + Python Core team +friendlies. **Not** a public marketplace skill — adoption is by +invitation while the framework is pre-release; once we ship via +the [ASF release policy](https://www.apache.org/legal/release-policy.html), +the marketplace path opens up. See +[release-distribution](https://infra.apache.org/release-distribution.html) +for the canonical distribution mechanism we will adopt. + +## How adoption works + +The framework uses a **snapshot + agentic-override** adoption +model. An adopter project commits a single skill — +[`setup-steward`](.claude/skills/setup-steward/SKILL.md) — +into their repo. That skill manages everything else: + +1. **Snapshot.** `setup-steward` downloads the framework into + a **gitignored** `/.apache-steward/` directory. + The snapshot is a build artefact, not source — refreshed + by `/setup-steward upgrade`, never committed. +2. **Symlinks.** `setup-steward` symlinks the framework's + skills (security, pr-management, the rest of setup) into + the adopter's existing skill directory, matching whichever + convention the adopter uses (flat `.claude/skills/`, or the + double-symlink `.claude/skills/` → `.github/skills//` + pattern apache/airflow uses). The symlinks are **also + gitignored** — they target the gitignored snapshot, so they + would dangle on a fresh clone before `/setup-steward` runs. +3. **Overrides.** Adopter-specific modifications to framework + workflows live as agent-readable markdown under + `/.apache-steward-overrides/.md`, + **committed** in the adopter repo. The framework's skills + consult those files at run-time and apply the overrides + before executing default behaviour. See + [`docs/setup/agentic-overrides.md`](docs/setup/agentic-overrides.md) + for the contract. + +**No git submodules. No marketplace. No vendored copies of +framework skills.** Just one committed skill (the bootstrap), +a gitignored snapshot, and agent-readable override files. + +## Adopting the framework + +Tell your agent: **"adopt apache/airflow-steward in my repo"**. + +The agent should: + +1. Read this README (you're here). +2. Copy the + [`setup-steward`](.claude/skills/setup-steward/SKILL.md) + skill from this framework into your repo's skill directory, + matching your existing convention (flat `.claude/skills/` or + the double-symlinked pattern — see + [`conventions.md`](.claude/skills/setup-steward/conventions.md)). + This is the **only** framework artefact the adopter commits. +3. Invoke `/setup-steward` to do the rest: + + - download the snapshot into `.apache-steward/` (gitignored), + - create symlinks in your skill directory for the families + you pick (security and/or pr-management), + - scaffold `.apache-steward-overrides/` (committed), + - update your repo's `.gitignore`, + - install a `post-checkout` git hook so worktrees re-create + the gitignored symlinks automatically, + - update your project documentation with a brief mention. + +After the skill finishes, you commit the small, focused +diff — the bootstrap skill, the `.gitignore` entries, the +overrides scaffold, the doc note — and you're done. Open a PR. ## Skill families -The framework ships three independent skill families. **Setup** is -a prerequisite for every other family — it installs the secure -agent setup that makes the other skills safe to run against -pre-disclosure content. **Security** and **PR management** are -options the adopter picks based on what the project needs to -automate. +Three skill families ship in the framework. Pick whichever the +adopter wants to use; symlinks for the picked families land in +the adopter's skill directory. | Family | Purpose | Detail | |---|---|---| -| [**setup**](docs/setup/README.md) | Isolated agent setup — sandboxing, pinned tools, framework upgrades. The prerequisite. | 6 skills, [`docs/setup/`](docs/setup/) | -| [**security**](docs/security/README.md) | 16-step security-issue handling lifecycle — from `security@` import through CVE publication. | 8 skills, [`docs/security/`](docs/security/) | +| [**setup**](docs/setup/README.md) | Isolated agent setup, framework adoption + maintenance, shared-config sync. The prerequisite — at minimum the `setup-steward` skill itself runs out of this family. | 6 skills, [`docs/setup/`](docs/setup/) | +| [**security**](docs/security/README.md) | 16-step security-issue handling lifecycle — from `security@` import through CVE publication. Maintainer-only. | 8 skills, [`docs/security/`](docs/security/) | | [**pr-management**](docs/pr-management/README.md) | Maintainer-facing PR-queue management — triage, stats, deep code review. | 3 skills, [`docs/pr-management/`](docs/pr-management/) | -## Adopting the framework +## Maintenance + +After the initial adoption, the same skill handles ongoing +maintenance: -Three one-time steps to integrate the framework into a new tracker -or upstream repo: - -1. **Add the framework as a submodule** at - `.apache-steward/apache-steward/`: - - ```bash - cd path/to/your/repo - git submodule add https://github.com/apache/airflow-steward .apache-steward/apache-steward - ``` - -2. **Copy the [`projects/_template/`](projects/_template/) - scaffold** into `.apache-steward/`, then `grep -rn TODO - .apache-steward/` to find every placeholder you need to fill in. - The required files vary by which skill families you adopt — - see the per-family adopter contract in each - [`docs//README.md`](docs/) and the file-by-file index - in - [`projects/_template/README.md`](projects/_template/README.md). - - ```bash - cp -r .apache-steward/apache-steward/projects/_template/. .apache-steward/ - ``` - -3. **Symlink `.claude/skills/`** to the framework's skill - directory, so Claude Code (or another `SKILL.md`-aware agent) - loads the framework's skills against your project configuration: - - ```bash - ln -s .apache-steward/apache-steward/.claude/skills .claude/skills - ``` - -The framework's -[`setup-steward-verify`](.claude/skills/setup-steward-verify/SKILL.md) -skill checks each of these and reports `✓ done / ✗ missing / -⚠ partial` for the adopter integration — run it after step 3 to -confirm the install landed. - -## Keeping the submodule current - -**Always run `git submodule update --init --recursive` after every -pull on the tracker repository.** A plain `git pull` advances the -framework submodule *pointer* in the index but does **not** update -the framework's working tree — skills will run against the -*previous* version after any pull that bumped the pointer. Wire it -into a post-merge hook to make it automatic: - -```bash -cat >.git/hooks/post-merge <<'SH' -#!/bin/sh -exec git submodule update --init --recursive -SH -chmod +x .git/hooks/post-merge -``` - -The framework's -[`setup-steward-upgrade`](.claude/skills/setup-steward-upgrade/SKILL.md) -skill upgrades the framework checkout itself; if the user is -consuming the framework as a tracker submodule, the skill reminds -them to follow up with submodule update on the parent tracker. +- `/setup-steward upgrade` — refresh the snapshot to a newer + framework version + reconcile any overrides against the new + framework structure. +- `/setup-steward verify` — read-only health check (snapshot + intact, symlinks live, `.gitignore` correct, etc.). +- `/setup-steward override ` — open or + scaffold an override file for a framework skill. ## Cross-references -- [`docs/prerequisites.md`](docs/prerequisites.md) — what a triager, - remediation developer, release manager, or PR maintainer needs - installed before invoking any framework skill (Claude Code, - Gmail MCP, GitHub auth, browser, `uv`, etc.). -- [`AGENTS.md`](AGENTS.md) — agent instructions, placeholder - convention, framework conventions. -- [`CONTRIBUTING.md`](CONTRIBUTING.md) — for framework - contributors. -- [`projects/_template/`](projects/_template/) — the adopter- - scaffold directory you copy into `/`. +- [`docs/setup/agentic-overrides.md`](docs/setup/agentic-overrides.md) — the contract between adopters who write overrides and framework skills that read them. +- [`docs/prerequisites.md`](docs/prerequisites.md) — what a maintainer needs installed before invoking any framework skill (Claude Code, Gmail MCP, GitHub auth, browser, `uv`, etc.). +- [`AGENTS.md`](AGENTS.md) — agent instructions, placeholder convention, framework conventions. +- [`CONTRIBUTING.md`](CONTRIBUTING.md) — for framework contributors. diff --git a/docs/setup/agentic-overrides.md b/docs/setup/agentic-overrides.md new file mode 100644 index 00000000..f322780a --- /dev/null +++ b/docs/setup/agentic-overrides.md @@ -0,0 +1,248 @@ + + +**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* + +- [Agentic overrides — modifying framework workflows in an adopter](#agentic-overrides--modifying-framework-workflows-in-an-adopter) + - [Where override files live](#where-override-files-live) + - [What an override file may contain](#what-an-override-file-may-contain) + - [Skip a step](#skip-a-step) + - [Replace a step](#replace-a-step) + - [Add a step](#add-a-step) + - [Pre-empt a decision-table row](#pre-empt-a-decision-table-row) + - [What an override file should explain](#what-an-override-file-should-explain) + - [How a framework skill consults overrides](#how-a-framework-skill-consults-overrides) + - [Hard rules](#hard-rules) + - [Reconciliation on framework upgrade](#reconciliation-on-framework-upgrade) + - [Upstreaming an override](#upstreaming-an-override) + - [Why agentic, not declarative?](#why-agentic-not-declarative) + - [Cross-references](#cross-references) + + + + + +# Agentic overrides — modifying framework workflows in an adopter + +The framework's skills are project-agnostic by design. An +adopter project that needs to modify a framework workflow's +behaviour — different defaults, an extra step, a skipped step, +a different tone — does **not** fork the framework, does **not** +modify the framework's snapshot in `.apache-steward/`, and does +**not** copy a framework skill into their own +`.claude/skills/`. Instead, they write an **override file**: +agent-readable markdown that the framework skill consults at +run-time and applies before executing default behaviour. + +This document is the **contract** between adopter authors of +override files and framework authors of skills that read them. + +## Where override files live + +```text +/.apache-steward-overrides/ +├── README.md (the dir's own readme, +│ scaffolded by +│ /setup-steward adopt) +├── .md (e.g. pr-management-triage.md) +└── .md +``` + +The directory is **committed** in the adopter repo (the whole +point is for overrides to ship with the project's repo). + +## What an override file may contain + +Free-form agent-readable markdown. The agent interprets it. No +templating engine, no patch tool, no DSL. The override author +writes what they want to change, and the framework skill applies +it on every invocation. + +Common shapes: + +### Skip a step + +```markdown +### Override 1 — Skip the workflow-approval auto-approve + +For first-time-contributor PRs, the default flow approves the +workflow run automatically after diff inspection. Skip that +step entirely; we approve workflow runs by hand on this repo. +``` + +### Replace a step + +```markdown +### Override 2 — Replace the close-comment template + +Replace the body the `close` action posts with the project- +specific wording in +[`/.github/CONTRIBUTING-pr-quality.md`](../.github/CONTRIBUTING-pr-quality.md) +section *"PRs we close as out of scope"*. Keep the AI-attribution +footer. +``` + +### Add a step + +```markdown +### Override 3 — Always tag @core-maintainers on first comment + +Before posting any comment on a PR for the first time, add a +`@apache/airflow-core-maintainers` mention so the team gets a +notification. Do not add it on subsequent comments on the same +PR. +``` + +### Pre-empt a decision-table row + +```markdown +### Override 4 — Treat backport PRs as already-triaged + +Any PR whose base branch matches `v[0-9]-[0-9]-test` is +auto-classified as `already-triaged` regardless of triage +markers. Skip the `mark-ready` action; backports go straight to +the `pr-management-code-review` queue when their CI passes. +``` + +## What an override file should explain + +Every override file should answer two questions for a future +maintainer (or a future agent on a later run): + +1. **Why does this adopter need to deviate from the + framework's default?** Often the answer is a project- + specific convention, an existing tool the framework + doesn't know about, or a deliberate softer/harder stance + on a default policy. +2. **Should this be upstreamed?** If the override is widely + useful, it belongs in the framework. The override file + says so explicitly, and the next person running the + `/setup-steward override ` flow takes the cue and + opens a PR against `apache/airflow-steward`. + +## How a framework skill consults overrides + +Every framework skill that supports overrides starts each +invocation with this opening protocol: + +1. Read `/.apache-steward-overrides/.md` + if it exists. Surface the file's title and the list of + override headlines (`### Override N — ...`) to the user + before doing anything else. +2. Apply the overrides: each `### Override N — ...` section + modifies the skill's default behaviour for this run. The + agent interprets the instructions in the override section + and adjusts the rest of the skill's flow accordingly. +3. After the skill finishes, recap which overrides were + applied (and any the agent decided not to apply with the + reasoning), so the user has an audit trail. + +A skill that does **not** yet support overrides documents +that explicitly in its `SKILL.md`. The +[`setup-steward override`](../../.claude/skills/setup-steward/overrides.md) +sub-action surfaces this gap and suggests opening a +framework-side issue requesting the hook. + +## Hard rules + +These are baked into agent instructions across the framework. +A framework agent NEVER: + +- Modifies the snapshot under + `/.apache-steward/`. The snapshot is a build + artefact — every modification gets blown away on the next + `/setup-steward upgrade`. Local mods go into + `.apache-steward-overrides/`. +- Proposes overrides be merged in by editing the framework + source in the snapshot. Framework changes go via PR to + `apache/airflow-steward`. +- Auto-rewrites override files on framework upgrades. When + a framework upgrade restructures a skill that has an + override, the agent surfaces the conflict and lets the + human decide (the override expresses adopter intent — + re-anchoring it correctly is human judgement, not + pattern-matching). + +## Reconciliation on framework upgrade + +When `/setup-steward upgrade` refreshes the snapshot, it +walks every override file and surfaces: + +- Overrides whose target framework skill no longer exists + (renamed or removed). +- Overrides that reference framework structure (step + numbers, golden rules, decision-table rows) that has + changed in the new framework version. + +Both are surfaced as ⚠ — non-blocking, but the user re- +anchors the override against the new framework structure +before relying on it again. Until re-anchored, the framework +skill applies what it can interpret from the override and +reports anything it skipped. + +## Upstreaming an override + +If an adopter project's override is widely useful (e.g. a +behaviour the framework should ship by default for all +adopters), the right move is **a PR against the framework**: + +1. Read the latest `apache/airflow-steward` `main`. +2. Implement the change in the framework skill's source. +3. Open the PR. +4. Once merged, the next `/setup-steward upgrade` in the + adopter pulls the framework change. +5. The adopter's now-redundant override gets deleted. + +The +[`setup-steward override`](../../.claude/skills/setup-steward/overrides.md) +sub-action prompts the user about upstreaming on every +override scaffold; the +[`security-issue-fix`](../../.claude/skills/security-issue-fix/SKILL.md) +and +[`pr-management-code-review`](../../.claude/skills/pr-management-code-review/SKILL.md) +skills know how to open a public PR — point them at the +framework repo. + +## Why agentic, not declarative? + +The first cut of an override mechanism would be templated: +a YAML schema, declared anchors per skill step, a runtime +patch. We deliberately rejected that: + +- **Schemas drift.** Every framework restructure breaks + every adopter's overrides. The framework's authors have + to maintain backward-compatible anchor tags forever, or + every upgrade is a synchronised override-rewrite event + across every adopter. +- **Schemas force pre-thought.** The framework would have + to anticipate every override an adopter might want and + surface anchors for it. The agentic mechanism inverts + this: adopters describe what they want, the agent figures + out how to apply it against whatever shape the framework + currently has. The framework is free to restructure; + overrides are free to express intent in whatever + granularity the user finds natural. +- **Agents already interpret natural-language workflow + changes**. The whole framework is agent-readable + markdown — having overrides be the same lets the agent + apply them with the same comprehension primitives as + the underlying skills. + +Trade-off: agentic interpretation has variance. An override +that says "always tag @core-maintainers" might be applied +slightly differently across runs. The mechanism mitigates +this by: + +1. Surfacing override application *before* skill execution + so the user can correct ambiguity. +2. Recapping override application *after* skill execution + for audit. +3. Keeping override files small and specific (the + `/setup-steward override` flow encourages one focused + override per file, not a sprawling rewrite). + +## Cross-references + +- [`setup-steward` skill](../../.claude/skills/setup-steward/SKILL.md) — the entry point that manages the snapshot + scaffolds overrides. +- [`overrides.md` sub-action](../../.claude/skills/setup-steward/overrides.md) — interactive override creation. +- [Top-level README](../../README.md) — adoption flow.