This is an automated email from the ASF dual-hosted git repository.
potiuk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow-steward.git
The following commit(s) were added to refs/heads/main by this push:
new e501d82 refactor(skills): migrate config/user.md references to
.apache-steward-overrides/user.md (#45)
e501d82 is described below
commit e501d8200c7228ae6c543ae5297295a5d683b639
Author: André Ahlert <[email protected]>
AuthorDate: Mon May 4 11:18:14 2026 -0300
refactor(skills): migrate config/user.md references to
.apache-steward-overrides/user.md (#45)
The framework adopted a snapshot+overrides architecture in PR #38.
Under that design, per-user configuration (PMC status, local clone
paths, optional tool backends) lives in the adopter repo, not in the
framework. The security skills, however, still referenced the legacy
config/user.md path from the pre-snapshot architecture.
Changes:
- Update 4 security skills (sync, import, fix, cve-allocate) to read
from .apache-steward-overrides/user.md instead of config/user.md.
- Add Step 9b to setup-steward/adopt.md to scaffold a user.md
template during first-time adoption.
- Update docs and tool adapters that referenced config/user.md:
onboarding, prerequisites, gmail, ponymail, fix-workflow template.
The fallback-interactive behaviour is preserved: when the file is
missing, skills ask the user and offer to save the answer back.
Fixes the structural gap where the framework docs described a config/
layer that was never created in the snapshot-based architecture.
Signed-off-by: André Ahlert <[email protected]>
---
.claude/skills/security-cve-allocate/SKILL.md | 2 +-
.claude/skills/security-issue-fix/SKILL.md | 10 ++---
.claude/skills/security-issue-import/SKILL.md | 6 +--
.claude/skills/security-issue-sync/SKILL.md | 10 ++---
.claude/skills/setup-steward/adopt.md | 57 +++++++++++++++++++++++++++
docs/prerequisites.md | 2 +-
docs/security/new-members-onboarding.md | 20 +++++-----
projects/_template/fix-workflow.md | 2 +-
tools/gmail/draft-backends.md | 4 +-
tools/gmail/operations.md | 2 +-
tools/gmail/tool.md | 2 +-
tools/ponymail/tool.md | 2 +-
12 files changed, 87 insertions(+), 32 deletions(-)
diff --git a/.claude/skills/security-cve-allocate/SKILL.md
b/.claude/skills/security-cve-allocate/SKILL.md
index 39652c4..77b91d5 100644
--- a/.claude/skills/security-cve-allocate/SKILL.md
+++ b/.claude/skills/security-cve-allocate/SKILL.md
@@ -179,7 +179,7 @@ Before touching the tracker, verify:
tell the user up front to install `uv` (one command:
`curl -LsSf https://astral.sh/uv/install.sh | sh`).
3. **Resolve the user's PMC status.** First try to read it from
- [`config/user.md`](../../../config/user.md) → `role_flags.pmc_member`
+ `.apache-steward-overrides/user.md` → `role_flags.pmc_member`
(see [`config/README.md`](../../../config/README.md) for the config
layer explainer). If the file exists and the flag is set, use that
value and surface it in the Step 0 recap (*"loaded config for
diff --git a/.claude/skills/security-issue-fix/SKILL.md
b/.claude/skills/security-issue-fix/SKILL.md
index b25ead4..43d2424 100644
--- a/.claude/skills/security-issue-fix/SKILL.md
+++ b/.claude/skills/security-issue-fix/SKILL.md
@@ -148,10 +148,10 @@ tracker only to discover you cannot push the branch.
directly — a fork is required.
- **A clean local clone of `<upstream>`** reachable from the
agent's working directory. The path comes from the user's
- [`config/user.md`](../../../config/user.md) →
+ `.apache-steward-overrides/user.md` →
`environment.upstream_clone`; if the file or key is missing,
the skill asks the user interactively and offers to save the
- answer back into `config/user.md` so the next run is silent. The
+ answer back into `.apache-steward-overrides/user.md` so the next run is
silent. The
skill does **not** guess filesystem layouts — there is no
hard-coded search path. The clone must:
- have a remote pointing at your fork;
@@ -313,14 +313,14 @@ change; it writes into a local clone of `<upstream>`.
Before
touching any files:
1. Resolve the clone path from the user's
- [`config/user.md`](../../../config/user.md) →
+ `.apache-steward-overrides/user.md` →
`environment.upstream_clone` (see
[`config/README.md`](../../../config/README.md) for the config
layer explainer). If the file is missing, the key is unset, or
the stored path does not resolve to a git repo with a remote
pointing at `<upstream>` or the user's fork, **ask the user
for the path interactively** and offer to save their answer back
- into `config/user.md` so the next run is silent. Do **not**
+ into `.apache-steward-overrides/user.md` so the next run is silent. Do
**not**
probe hard-coded paths like `~/code/airflow` — filesystem layouts
vary per user and a wrong guess masks a misconfigured clone.
@@ -328,7 +328,7 @@ touching any files:
and which is the upstream `<upstream>`. Per the rule in
[`<upstream>/AGENTS.md`](https://github.com/<upstream>/blob/main/AGENTS.md),
push only to the user's fork, never to `<upstream>` directly.
- If the user's `config/user.md` has
+ If the user's `.apache-steward-overrides/user.md` has
`environment.upstream_fork_remote` set, prefer that remote
name; otherwise use the first non-`origin` remote that looks like
a fork. If no fork remote is configured, **stop and ask the user
diff --git a/.claude/skills/security-issue-import/SKILL.md
b/.claude/skills/security-issue-import/SKILL.md
index 1ff9f17..63bd4df 100644
--- a/.claude/skills/security-issue-import/SKILL.md
+++ b/.claude/skills/security-issue-import/SKILL.md
@@ -173,7 +173,7 @@ Before touching any candidate thread, verify:
(401, 403, 404), stop and tell the user to log in with
`gh auth login` or get added to `<tracker>`.
3. **PonyMail MCP status** (opt-in; primary read path when
- enabled) — read `config/user.md` → `tools.ponymail`. If
+ enabled) — read `.apache-steward-overrides/user.md` → `tools.ponymail`. If
`enabled: true`, call `mcp__ponymail__auth_status()` once and
record `ponymail_enabled` + `ponymail_authenticated` in the
skill's observed-state bag. **When authenticated, downstream
@@ -246,7 +246,7 @@ lags the inbox by minutes-to-hours for brand-new messages,
which
is exactly the window this skill most cares about.
When PonyMail MCP is enabled and authenticated (Step 0) **and**
-`security@<project>.apache.org` is in `config/user.md` →
+`security@<project>.apache.org` is in `.apache-steward-overrides/user.md` →
`tools.ponymail.private_lists`, run the archive as a **paired
authoritative check** against the Gmail result set:
@@ -550,7 +550,7 @@ in short:
**Backend selection.** When PonyMail MCP is enabled and
authenticated (Step 0) **and** `security@<project>.apache.org`
-is in `config/user.md` → `tools.ponymail.private_lists`,
+is in `.apache-steward-overrides/user.md` → `tools.ponymail.private_lists`,
**PonyMail MCP is the primary backend for this step**:
```text
diff --git a/.claude/skills/security-issue-sync/SKILL.md
b/.claude/skills/security-issue-sync/SKILL.md
index e700eaf..8364ce4 100644
--- a/.claude/skills/security-issue-sync/SKILL.md
+++ b/.claude/skills/security-issue-sync/SKILL.md
@@ -347,7 +347,7 @@ Before reading any tracker state, verify:
`<tracker>`. A 401/403/404 means the user needs
`gh auth login` or collaborator access.
3. **PonyMail MCP status** (opt-in; primary read path when
- enabled) — read `config/user.md` → `tools.ponymail`. If
+ enabled) — read `.apache-steward-overrides/user.md` → `tools.ponymail`. If
`enabled: true`, call `mcp__ponymail__auth_status()` once. Three
outcomes:
- **Authenticated session** — record
@@ -371,7 +371,7 @@ Before reading any tracker state, verify:
user who set `enabled: true` in config but has not
registered the MCP in Claude Code's `mcpServers` block gets
the Gmail-only path without a noisy error.
- When `config/user.md` sets `enabled: false` or omits the
+ When `.apache-steward-overrides/user.md` sets `enabled: false` or omits the
`ponymail` block entirely, skip this sub-step; Gmail is the
only read backend. See
[`tools/ponymail/tool.md`](../../../tools/ponymail/tool.md)
@@ -475,7 +475,7 @@ set is the strongest signal for what milestone the security
issue should carry.
**Backend selection.** When Step 0 recorded
`ponymail_authenticated: true` **and**
-`security@<project>.apache.org` is in `config/user.md` →
+`security@<project>.apache.org` is in `.apache-steward-overrides/user.md` →
`tools.ponymail.private_lists`, **PonyMail MCP is the primary
backend for this step** — the archive is authoritative and
reaches back further than any single user's Gmail window. Run the
@@ -613,7 +613,7 @@ it for: historical lookups, cross-list fan-outs
reliably find messages older than ~90 days. Gmail is the fallback
when (a) PonyMail is not enabled / not authenticated, (b) a
private list the query targets is not in
-`config/user.md` → `tools.ponymail.private_lists`, or (c) the
+`.apache-steward-overrides/user.md` → `tools.ponymail.private_lists`, or (c)
the
signal is *just-arrived inbound mail* where Gmail's inbox latency
beats the archive's indexing delay. The per-issue budget is
≤ 2 archive searches (whichever backend) plus ≤ 3 Gmail inbox
@@ -720,7 +720,7 @@ uses for reporter threads. That is the load-bearing signal
path.
**Backend selection.** When PonyMail MCP is enabled and
authenticated (Step 0) **and** `security@<project>.apache.org` is
-in `config/user.md` → `tools.ponymail.private_lists`, **PonyMail
+in `.apache-steward-overrides/user.md` → `tools.ponymail.private_lists`,
**PonyMail
MCP is the primary path** for reviewer-comment archive queries:
```text
diff --git a/.claude/skills/setup-steward/adopt.md
b/.claude/skills/setup-steward/adopt.md
index b1680e5..2e3aa0c 100644
--- a/.claude/skills/setup-steward/adopt.md
+++ b/.claude/skills/setup-steward/adopt.md
@@ -230,6 +230,63 @@ Framework changes go via PR to `apache/airflow-steward`.
This directory is **committed** (overrides ship with the
adopter repo).
+## Step 9b — Scaffold `.apache-steward-overrides/user.md` (FRESH only)
+
+Create `<repo-root>/.apache-steward-overrides/user.md` with a
+project-agnostic template. The security skills read this file at
+run-time to resolve per-user preferences (PMC status, local clone
+paths, optional tool backends). If the file is missing, the skills
+fall back to interactive prompting and offer to save the answer
+back into this file.
+
+```markdown
+# Per-user configuration for apache-steward
+
+This file is committed in the adopter repo and holds preferences
+that vary per developer (GitHub handle, local clone paths, optional
+tool backends). It is **not** project-specific — those facts live in
+`<project-config>/project.md`. Fill in the fields that apply to your
+setup; the skills skip any block that is missing or marked `TODO`.
+
+## `role_flags`
+
+- `pmc_member: TODO` — set to `true` if you are a PMC member of the
+ adopting project. Used by `security-cve-allocate` to decide whether
+ you can submit the CVE allocation form directly or need to relay
+ the request to a PMC member.
+
+## `environment`
+
+- `upstream_clone: TODO` — absolute path to your local clone of the
+ public `<upstream>` repo. Used by `security-issue-fix` when it
+ writes changes and opens PRs. The skill validates that the clone
+ has a remote pointing at your fork before proceeding.
+- `upstream_fork_remote: TODO` — name of the git remote that points
+ at your personal fork (e.g. `fork`, `your-github-handle`). If
+ omitted, the skill uses the first non-`origin` remote that looks
+ like a fork. Explicitly setting this avoids ambiguity when you
+ have multiple remotes.
+
+## `tools`
+
+### `ponymail`
+
+- `enabled: false` — set to `true` if you have registered the
+ PonyMail MCP in your Claude Code `mcpServers` block. When enabled
+ and authenticated, the security skills use PonyMail as the primary
+ read backend for mailing-list archive queries; Gmail remains the
+ fallback for just-arrived inbound mail and the only backend for
+ draft composition.
+- `private_lists: []` — list of private mailing-list addresses that
+ PonyMail should query (e.g. `["security@<project>.apache.org"]`).
+ Only used when `enabled: true`.
+```
+
+Show the file to the user and offer to fill in the `TODO` fields
+interactively (one prompt per field, skipping any the user does not
+yet know). After the interactive fill, write the file to disk and
+git-add it.
+
## Step 10 — Worktree-aware post-checkout hook (FRESH only)
Install
diff --git a/docs/prerequisites.md b/docs/prerequisites.md
index a45ae1f..76930ff 100644
--- a/docs/prerequisites.md
+++ b/docs/prerequisites.md
@@ -131,7 +131,7 @@ checks and tests, pushes a branch to your fork, and opens a
PR via
`gh pr create --web`. You need:
- a clean clone of `<upstream>` reachable from the agent's working
- directory — the path comes from `config/user.md →
+ directory — the path comes from `.apache-steward-overrides/user.md →
environment.upstream_clone`, set interactively the first time
you run the skill;
- the adopting project's dev toolchain installed per its contributing
diff --git a/docs/security/new-members-onboarding.md
b/docs/security/new-members-onboarding.md
index 007ece8..05ed5ab 100644
--- a/docs/security/new-members-onboarding.md
+++ b/docs/security/new-members-onboarding.md
@@ -119,13 +119,12 @@ week. A good starting routine:
name — leaves the private channels.
6. **Set up your per-user config** if (and only if) you plan to run
the agent skills. Copy
- [`config/user.md.example`](config/user.md.example) to
- `config/user.md` and fill in your GitHub handle, email, PMC status,
- and (for remediation-developer work) the path to your local
- `<upstream>` clone. The full tutorial is in
- [`config/README.md`](config/README.md) — it takes under five
- minutes. You can skip this step on day one; skills fall back to
- runtime prompts when `config/user.md` is missing.
+ `.apache-steward-overrides/user.md` (scaffolded automatically when
+ the project adopts steward) and fill in your GitHub handle, email,
+ PMC status, and (for remediation-developer work) the path to your
+ local `<upstream>` clone. You can skip this step on day one;
+ skills fall back to runtime prompts when
+ `.apache-steward-overrides/user.md` is missing.
You can start commenting on issues on day one. Just commenting,
voting on validity, suggesting severity — those are valuable
@@ -193,7 +192,7 @@ remediation-developer turn:
pre-fix sync, reads the discussion on the tracker to build a fix
plan, shows you the plan, and — only after you confirm — writes the
change in your local `<upstream>` clone (path from
- `config/user.md → environment.upstream_clone`), runs the local
+ `.apache-steward-overrides/user.md → environment.upstream_clone`), runs the
local
checks and tests, and opens a public `gh pr create --web` PR from
your fork. Every public surface (commit message, branch name, PR
title, PR body, newsfragment) is scrubbed for CVE / the tracker
@@ -230,9 +229,8 @@ shape the team are small enough to read in one sitting:
- [`README.md`](../../README.md) — the end-to-end handling process.
-
[`<project-config>/canned-responses.md`](<project-config>/canned-responses.md)
— reply templates.
- [`AGENTS.md`](../../AGENTS.md) — agent-facing conventions and
confidentiality rules.
-- [`config/README.md`](config/README.md) — how the per-project and
- per-user configuration layers work, with a tutorial for your own
- `config/user.md`.
+- `.apache-steward-overrides/user.md` — per-user configuration (PMC status,
+ local clone paths, optional tool backends) scaffolded during adoption.
- [`<project-config>/`](<project-config>/) — project-specific content
(roster, release trains, security model, scope labels, milestones,
canned responses, fix-workflow specifics) — lives in the adopter's
diff --git a/projects/_template/fix-workflow.md
b/projects/_template/fix-workflow.md
index 0a87bb7..9a77f12 100644
--- a/projects/_template/fix-workflow.md
+++ b/projects/_template/fix-workflow.md
@@ -51,7 +51,7 @@ TODO: list the project's developer toolchain. Example shape:
The `security-issue-fix` skill assumes a clean clone of `<upstream>`
reachable from the agent's working directory (path from
-`config/user.md → environment.upstream_clone`), with a remote named
+`.apache-steward-overrides/user.md → environment.upstream_clone`), with a
remote named
for the user's GitHub fork that `gh pr create` can push to.
## Backport labels
diff --git a/tools/gmail/draft-backends.md b/tools/gmail/draft-backends.md
index 92fffe3..5457528 100644
--- a/tools/gmail/draft-backends.md
+++ b/tools/gmail/draft-backends.md
@@ -22,7 +22,7 @@
# Gmail drafting backends
The skills create Gmail drafts via one of two backends, selected by the
-user in [`config/user.md`](../../config/user.md) under
+user in `.apache-steward-overrides/user.md` under
`tools.gmail.draft_backend`:
| Backend | Value | `threadId` attach? | Setup |
@@ -70,7 +70,7 @@ on disk, the skills should always use them. Resolution:
1. **Probe for `oauth_curl` credentials** in this order:
- `tools.gmail.oauth_credentials_path` from
- [`config/user.md`](../../config/user.md) when set;
+ `.apache-steward-overrides/user.md` when set;
- the `$GMAIL_OAUTH_CREDENTIALS` environment variable;
- the default path `~/.config/apache-steward/gmail-oauth.json`.
diff --git a/tools/gmail/operations.md b/tools/gmail/operations.md
index 0d75e26..2252d1d 100644
--- a/tools/gmail/operations.md
+++ b/tools/gmail/operations.md
@@ -99,7 +99,7 @@ only fetch bodies for the narrow set that actually warrants it
### Drafting backends
Draft creation runs through one of two backends, selected by the user
-in [`config/user.md`](../../config/user.md) under
+in `.apache-steward-overrides/user.md` under
`tools.gmail.draft_backend`. The full comparison and rationale live
in [`draft-backends.md`](draft-backends.md); the call shape per
backend is here.
diff --git a/tools/gmail/tool.md b/tools/gmail/tool.md
index d3ce70f..1067049 100644
--- a/tools/gmail/tool.md
+++ b/tools/gmail/tool.md
@@ -55,7 +55,7 @@ cannot compose reporter replies.
**Role when PonyMail MCP is opted into.** When a user sets
`tools.ponymail.enabled: true` in their
-[`config/user.md`](../../config/README.md) and authenticates the
+`.apache-steward-overrides/user.md` and authenticates the
MCP, PonyMail becomes the primary read backend for archive
queries (reporter-thread lookups, reviewer-comment searches,
`users@` / `dev@` archive scans, prior-rejection precedents).
diff --git a/tools/ponymail/tool.md b/tools/ponymail/tool.md
index d28ec4d..1015476 100644
--- a/tools/ponymail/tool.md
+++ b/tools/ponymail/tool.md
@@ -79,7 +79,7 @@ The two are **not** interchangeable today. Specifically:
**Primary vs. fallback.** When a project declares both tools in
its manifest **and** the user opts into PonyMail MCP in
-`config/user.md`, **PonyMail MCP is the primary read backend** for
+`.apache-steward-overrides/user.md`, **PonyMail MCP is the primary read
backend** for
archive queries (reporter-thread lookups, reviewer-comment
searches, advisory-URL scans, `[RESULT][VOTE]` attribution,
prior-rejection precedent searches). Gmail is the fallback —