Skip to content
Back to skills

Yaml Anchors

ASecurity

GitHub Actions parses workflow YAML with anchors and aliases since [18 September 2025](https://github.blog/changelog/2025-09-18-actions-yaml-anchors-and-non-public-workflow-templates/). GitHub rejects the merge key (`<<`), so an alias overrides nothing: a copy that differs by one key is out of an anchor's reach.

  • 4 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added September 10, 2026
devopspythonbashnodeexpressgitdatabase

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned September 10, 2026

npx -y skills add staticaland/skills --skill yaml-anchors --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Yaml Anchors?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Yaml Anchors
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/staticaland-yaml-anchors/badge)](https://www.skillsdirectory.com/skills/staticaland-yaml-anchors)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: yaml-anchors
description:
  Replace repeated configuration in a GitHub Actions workflow with YAML anchors
  and aliases. Use when the user wants a shorter workflow, mentions YAML anchors,
  or writes the same env, services, permissions, or path filter in more than one
  job of the same file.
version: 0.1.0
---

# YAML Anchors

GitHub Actions parses workflow YAML with anchors and aliases since
[18 September 2025](https://github.blog/changelog/2025-09-18-actions-yaml-anchors-and-non-public-workflow-templates/).
GitHub rejects the merge key (`<<`), so an alias overrides nothing: a copy that
differs by one key is out of an anchor's reach.

## Procedure

### 1. Inventory the repeated blocks

Read every workflow in `.github/workflows/`. Find the configuration written more
than once in the same file and record each copy's file, job, and key. These keys
hold most of the duplication.

- `env` maps shared by jobs
- `services` containers, such as a database or a cache
- `permissions`
- `paths`, `paths-ignore`, and `branches` filters under `on.push` and
  `on.pull_request`
- `runs-on`, when it names a set of self-hosted labels

Compare the copies of each block key by key and mark them identical or
different. Done when every repeated block has a site list and that verdict.

### 2. Identify anchor candidates

Anchor a block of three lines or more that is identical across two or more sites
in the same file.

Done when each candidate has a verdict: anchor or leave.

### 3. Anchor the identical blocks

Copy each workflow before you change it, so step 4 compares against the file as
it stood. `git show HEAD:<file>` returns the committed file, which is a
different document whenever the working tree already carries an edit.

```bash
cp .github/workflows/ci.yml /tmp/before.yml
```

- **Define on the first copy.** Put `&name` on the first copy in document order
  and `*name` on each later copy.
- **Anchor configuration that is already doing a job.** A workflow accepts eight
  top-level keys - `name`, `run-name`, `on`, `permissions`, `env`, `defaults`,
  `concurrency`, and `jobs` - so a workflow has nowhere to park a block of
  definitions.
- **Name the anchor after its content**, such as `&env_vars` or `&code_paths`.
- **Alias whole nodes.** An alias replaces a node. It appends to no list and
  overrides no key.
- **Keep the anchored expressions context-free.** An alias copies `${{ ... }}`
  as text, and the expression evaluates against the job that holds the alias, so
  `${{ matrix.node }}` inside an anchor expands to nothing in a job that has no
  matrix.

Done when each anchor has at least one alias, and each alias resolves to an
anchor written earlier in the file.

### 4. Verify

Run `actionlint` on each changed workflow.

```bash
actionlint .github/workflows/ci.yml
```

It reads anchors and aliases, and it reports a merge key by name:
`GitHub Actions does not support YAML merge key "<<"`. A YAML library reports
nothing there, because PyYAML follows YAML 1.1 and expands `<<` in silence.

Then prove the rewrite didn't change behavior.

```bash
python3 -c '
import sys, yaml
before, after = (yaml.safe_load(open(p)) for p in sys.argv[1:])
sys.exit(0 if before == after else "workflows differ")
' /tmp/before.yml .github/workflows/ci.yml
```

Where `import yaml` raises `ModuleNotFoundError`, run the same script through
`uv run --with pyyaml python -c` instead.

`zizmor` 1.29 audits every alias site and prints each finding at the anchor's
line. A finding repeated on one line describes a different job each time.

Report the blocks that an anchor cannot reach and the reason for each.

## Example

```yaml
on:
  push:
    paths: &code_paths
      - "src/**"
      - "package.json"
  pull_request:
    paths: *code_paths

jobs:
  test:
    runs-on: ubuntu-latest
    services: &postgres
      db:
        image: postgres:18
        env:
          POSTGRES_PASSWORD: postgres
        ports:
          - 5432:5432
    steps:
      - uses: actions/checkout@v6
      - run: npm test

  integration:
    runs-on: ubuntu-latest
    services: *postgres
    steps:
      - uses: actions/checkout@v6
      - run: npm run test:integration
```

[Reusing workflow configurations](https://docs.github.com/en/actions/reference/workflows-and-actions/reusing-workflow-configurations)
is the source of truth for anchors. If a rule here disagrees with that page,
obey the page.

Files in this skill

  • SKILL.md4.3 KB
  • agents/openai.yaml171 B

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.