Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 19 additions & 43 deletions .github/agents/adr-writer.agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,16 @@ Expert Architecture Decision Record (ADR) writer. Follow the **Michael Nygard AD

## ADR Philosophy

ADRs are permanent records of significant technical decisions: *"Why does the codebase look the way it does?"*

- **Immutable once accepted** — never deleted; superseded ones marked "Superseded by ADR-XXXX"
- **Decision-focused** — capture *why*, not just *what*
- **Honest about trade-offs** — include real negatives and costs
- **Written for future readers** — understandable 12 months later

## Storage Convention

ADRs live in `docs/adr/` as sequentially numbered Markdown files:
`docs/adr/NNNN-kebab-case-title.md` — `NNNN` is zero-padded 4 digits, lowercase kebab-case title, hyphens only.

```
docs/adr/
0001-use-postgresql-for-primary-storage.md
0002-adopt-hexagonal-architecture.md
0003-switch-from-rest-to-graphql.md
```

**Filename format**: `NNNN-kebab-case-title.md`
- `NNNN` zero-padded 4 digits (e.g., `0001`, `0042`)
- Lowercase kebab-case title
- Only hyphens as separators
Example: `docs/adr/0001-use-postgresql-for-primary-storage.md`

## ADR Template

Expand All @@ -45,23 +33,23 @@ docs/adr/

### Context

{Describe the situation, problem, and forces at play in plain language. What is the issue that motivated this decision? What constraints exist? What are the non-negotiable requirements? Write for a developer who is new to the codebase and needs background without reading the code. Keep this to 3–5 sentences.}
{Situation, problem, constraints, non-negotiable requirements. Write for a developer new to the codebase. 3–5 sentences.}

### Decision

{State the decision clearly using active voice. Start with "We will..." or "We decided to...". Explain the primary rationale in 2–4 sentences. This section should be unambiguous — a reader must know exactly what was decided.}
{Active voice: "We will..." or "We decided to...". Primary rationale. 2–4 sentences, unambiguous.}

### Alternatives Considered

#### Alternative 1: {Name}

{Description of the alternative. Why was it considered? Why was it not chosen? Be honest if it was a close call, say so.}
{What, why considered, why not chosen. Be honest if it was a close call.}

#### Alternative 2: {Name}

{Description of the alternative. Why was it considered? Why was it not chosen?}
{What, why considered, why not chosen.}

*(Add more alternatives as needed. Minimum 2 alternatives for non-trivial decisions.)*
*(Minimum 2 alternatives for non-trivial decisions.)*

### Consequences

Expand Down Expand Up @@ -95,24 +83,18 @@ docs/adr/
## Writing Quality Standards

#### Context (3–5 sentences)
- *What problem? What constraints?* (technical, organizational, timeline)
- Codebase state at decision time
- Problem space, not implementation
- Problem and constraints (technical, organizational, timeline)
- Codebase state at decision time; problem space, not implementation

#### Decision (2–4 sentences)
- Active voice: "We will use X because Y"
- Name the primary driver (performance, simplicity, cost, etc.)
- Name the pattern/principle if applicable
- Name primary driver (performance, simplicity, cost) and pattern/principle if applicable

#### Alternatives Considered (2–4 sentences each)
- **≥2 genuine alternatives** (no strawmen)
- For each: what, why considered, why rejected
- If close call, say so
- **≥2 genuine alternatives** (no strawmen); for each: what, why considered, why rejected

#### Consequences
- **Positive**: real benefits
- **Negative**: real costs and trade-offs
- **Neutral**: side effects worth noting
- **Positive**, **Negative**, **Neutral**: real benefits, costs, and side effects
- ≥2 per category for non-trivial decisions

## Procedure: Writing a New ADR
Expand All @@ -123,13 +105,11 @@ docs/adr/
ls docs/adr/*.md 2>/dev/null | grep -oP '\d{4}' | sort -n | tail -1
```

Start at `0001` if none exist; otherwise increment.
Start at `0001` if none; otherwise increment.

### Step 2: Derive the Filename

Kebab-case the title: lowercase, hyphens for spaces/specials, drop meaningless leading articles, 3–6 words.

Example: "Use PostgreSQL for Primary Storage" → `0001-use-postgresql-for-primary-storage.md`
Kebab-case: lowercase, hyphens, drop leading articles, 3–6 words. "Use PostgreSQL for Primary Storage" → `0001-use-postgresql-for-primary-storage.md`.

### Step 3: Ensure Directory

Expand All @@ -139,13 +119,13 @@ mkdir -p docs/adr

### Step 4: Analyze Context

- PR diff: identify implicit decisions
- Description: clarify decision and rationale
- PR diff: implicit decisions
- Description: decision and rationale
- Updating: read current version first

### Step 5: Write the ADR

Apply the template strictly. Fill every section. No placeholder text — mark unknowns `[TODO: verify]`.
Apply template strictly. Fill every section. Mark unknowns `[TODO: verify]`.

### Step 6: Save

Expand Down Expand Up @@ -179,13 +159,9 @@ For each: what problem? what alternatives? what consequences?

1. Read the ADR **Decision** — extract commitments
2. Check code for conformance/deviation
3. Note **divergences**: code contradicts decision
4. Note **scope creep**: significant decisions in code not covered
3. Note **divergences** (code contradicts decision) and **scope creep** (significant code decisions not covered)

Return:
- **Aligned**: code implements the ADR
- **Partially aligned**: minor divergences
- **Divergent**: significant contradictions
Return: **Aligned** (code implements ADR), **Partially aligned** (minor divergences), or **Divergent** (significant contradictions).

## Examples of ADR-Worthy Decisions

Expand Down
18 changes: 9 additions & 9 deletions .github/aw/workflow-constraints.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,15 +66,15 @@ When a requested feature increases risk:

## Self-Hosted Runner Compatibility

When a workflow targets a self-hosted runner (any `runs-on` value other than GitHub-hosted labels such as `ubuntu-latest`, `ubuntu-slim`, `windows-latest`, or `macos-latest`), keep the generated workflow compatible with self-hosted constraints:

- Set `runs-on` explicitly (it is not inherited from imports) to the runner the user's setup provides; `runs-on` accepts a string, array, or runner-group object. Framework/generated jobs (activation, safe-outputs, unlock, etc.) default to the hosted `ubuntu-slim`, so also set `runs-on-slim` to route them to the self-hosted runner, otherwise they try to run on a hosted runner. `runs-on-slim` accepts the same string, array, or runner-group object forms as `runs-on`.
- Write transient state, tool downloads, and intermediate outputs under `$RUNNER_TEMP`, not `/tmp`, which can persist across jobs on shared runners.
- The agent job's own steps run as the runner user, not root — don't write steps that assume root (for example, installing to system-wide paths). Separately, the egress firewall needs host-level privileges (sudo) on the runner; if the host cannot provide that, the firewall can be disabled, which removes egress filtering. Surface that trade-off to the user rather than encoding it in the workflow.
- Declare every outbound domain the workflow contacts in `network.allowed` (keep `defaults` for the core GitHub/Copilot/registry endpoints). When the egress firewall is enabled (the default once network permissions are set), any domain that is not allow-listed is blocked.
- Do not install to system-wide paths such as `/usr/local` or the toolcache — they may be read-only or shared across runners. Install into job-scoped writable paths instead.
- Do not hardcode `/home/runner` or any literal home path — read `$HOME` from the environment instead, and use `$RUNNER_TEMP` for transient state since it is guaranteed writable.
- For GitHub Enterprise Server, enable GHES compatibility so generated workflows use artifact action versions that work on GHES, and configure the enterprise API endpoint.
When `runs-on` is any value other than GitHub-hosted labels (`ubuntu-latest`, `ubuntu-slim`, `windows-latest`, `macos-latest`):

- Set `runs-on` explicitly (not inherited from imports); accepts string, array, or runner-group object. Framework jobs (activation, safe-outputs, unlock, etc.) default to hosted `ubuntu-slim`, so also set `runs-on-slim` (same forms) to route them to the self-hosted runner.
- Write transient state, tool downloads, and outputs under `$RUNNER_TEMP`, not `/tmp` (which can persist across jobs on shared runners).
- Agent steps run as the runner user, not root — don't install to system-wide paths. The egress firewall needs sudo; if unavailable, it can be disabled (removing egress filtering) — surface the trade-off to the user rather than encoding it.
- Declare every outbound domain in `network.allowed` (keep `defaults` for core GitHub/Copilot/registry endpoints). Non-allow-listed domains are blocked when the firewall is enabled.
- Do not install to `/usr/local` or the toolcache (may be read-only/shared); use job-scoped writable paths.
- Do not hardcode `/home/runner` or any literal home path — read `$HOME`; use `$RUNNER_TEMP` for transient state.
- For GitHub Enterprise Server, enable GHES compatibility (GHES-compatible artifact action versions, enterprise API endpoint).

For the full set of requirements (Docker socket, ARC / Docker-in-Docker, network egress, GHES specifics), follow the [Self-Hosted Runners](/gh-aw/reference/self-hosted-runners/) reference page.

Expand Down
Loading