Skip to content
Development
Skill

/setup-action

Sets up GitHub Actions for ESP32 projects — building ESP-IDF firmware in a pinned container, taking the version from the git tag, proving a published image is the variant it claims to be, and publishing artefacts and a release when a tag is pushed. Also covers the pre-merge

From plugin
embedded-ai-harness
16118 skills
Install
$ npx -y skills add SensorsIot/Embedded-AI-Harness --skill setup-action --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/setup-action

Context preview

The summary Claude sees to decide when to auto-load this skill.

Sets up GitHub Actions for ESP32 projects — building ESP-IDF firmware in a pinned container, taking the version from the git tag, proving a published image is the variant it claims to be, and publishing artefacts and a release when a tag is pushed. Also covers the pre-merge

SKILL.md

setup-action.SKILL.md
name: setup-action
description: Sets up GitHub Actions for ESP32 projects — building ESP-IDF firmware in a pinned container, taking the version from the git tag, proving a published image is the variant it claims to be, and publishing artefacts and a release when a tag is pushed. Also covers the pre-merge gate: lint plus the tests a hosted runner can actually run, and which tiers it cannot reach. Use this skill whenever CI comes up for an ESP32 or testbench project — a new project needing a build workflow, a release that should publish firmware, a gate that keeps turning red, or the question "why isn't this checked automatically". Triggers on "GitHub Action", "CI", "workflow", "pipeline", "build firmware in CI", "publish a release", "release on tag", ".github/workflows", "pre-merge check", "self-hosted runner", "lint on push".

CI for ESP32 projects

Two workflows with different jobs, and most projects want both:

| Workflow | Trigger | Answers | |---|---|---| | **build** | every push; publishes on a version tag | Can this be flashed, and where is the artefact? | | **gate** | every push and PR | May this change land? |

The build workflow is the substantial one and comes first below. The gate is simpler but has a rule that decides whether it is worth having at all: **a gate must be green from its first run**, or it teaches everyone to ignore a red tick.

Neither replaces hardware testing. A green tick means it compiles and the pure logic passes.

---

Part 1 — Build and publish firmware

Put this at `.github/workflows/build.yml` and fill in `<firmware-dir>`, `<app-name>` and `<target>`. Drop `working-directory` if the ESP-IDF project sits at the repository root.

**One build per run.** Most projects have one firmware, and the template defaults to that: `MULTI_VARIANT: 'false'` pins every run to production, and `<marker>` and `<alt-variant>` are then never read. Flip it to `'true'` only for a project that genuinely ships a second image, and read "Variants" below before you do.

name: Build Firmware

env:
  IDF_TAG: v6.0.2          # keep in step with the container tag below
  # The one switch for variant handling. Leave 'false' unless this project
  # really builds a second image; then set <marker> too.
  MULTI_VARIANT: 'false'
  VARIANT_MARKER: <marker>  # a string only the non-production image contains

on:
  push:
    branches: [main]
    tags: ['v*.*.*']
  workflow_dispatch:
    inputs:
      version:
        description: 'Version number (e.g. 1.2.0)'
        required: true
      variant:                       # inert while MULTI_VARIANT is 'false'
        description: 'Which firmware to build'
        type: choice
        options: [production, <alt-variant>]
        default: production

permissions:
  contents: write          # required to create the release

jobs:
  build:
    runs-on: ubuntu-latest
    container: espressif/idf:v6.0.2
    defaults:
      run:
        working-directory: <firmware-dir>
        shell: bash

    steps:
      # Must come first, and must not be skipped. The container runs as root
      # while the workspace belongs to the runner user, so every git call in a
      # `run:` step dies with "detected dubious ownership" — see "The container
      # runs as the wrong user" below.
      - name: Trust the workspace
        working-directory: ${{ github.workspace }}
        run: git config --global --add safe.directory '*'

      - uses: actions/checkout@v4
        with:
          fetch-depth: 0     # see "Versioning" below — tags are needed

      - name: Show the IDF version actually used
        run: . $IDF_PATH/export.sh >/dev/null && idf.py --version

      - name: Decide what to build
        id: plan
        run: |
          VARIANT="${{ github.event.inputs.variant || 'production' }}"
          [ "$MULTI_VARIANT" = "true" ] || VARIANT=production

          if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
            VERSION="${{ github.event.inputs.version }}"
          elif [[ "$GITHUB_REF" == refs/tags/v* ]]; then
            VERSION=${GITHUB_REF#refs/tags/v}
          else
            VERSION="0.0.0-$(git rev-parse --short HEAD)"
          fi

          DEFAULTS="sdkconfig.defaults"
          if [ "$VARIANT" != "production" ]; then
            DEFAULTS="sdkconfig.defaults;sdkconfig.$VARIANT.defaults"
            VERSION="$VERSION-$VARIANT"
          fi

          { echo "variant=$VARIANT"; echo "version=$VERSION"
            echo "defaults=$DEFAULTS"; } >> $GITHUB_OUTPUT
          echo "Building the $VARIANT firmware as $VERSION"

      # -DSDKCONFIG: keep the config in the build dir — see "sdkconfig" below.
      - name: Build firmware
        run: |
          . $IDF_PATH/export.sh >/dev/null
          ARGS="-B build -DSDKCONFIG=$PWD/build/sdkconfig \
                -DSDKCONFIG_DEFAULTS=${{ steps.plan.outputs.defaults }} \
                -DPROJECT_VER=${{ steps.plan.outputs.version }}"
          idf.py $ARGS set-target <target>
          idf.py $ARGS build

      - name: Verify the image matches the variant asked for
        if: env.MULTI_VARIANT == 'true'
        run: |
          grep -q "$VARIANT_MARKER" build/<app-name>.bin && FOUND=yes || FOUND=no
          WANT=no; [ "${{ steps.plan.outputs.variant }}" = "production" ] || WANT=yes
          if [ "$FOUND" != "$WANT" ]; then
            echo "FATAL: ${{ steps.plan.outputs.variant }} image, marker found=$FOUND, expected=$WANT"
            exit 1
          fi
          echo "verified: ${{ steps.plan.outputs.variant }} image, marker $FOUND"

      - name: Collect artefacts
        run: |
          V="${{ steps.plan.outputs.version }}"
          cp build/<app-name>.bin firmware_v${V}.bin
          cp build/<app-name>.elf firmware_v${V}.elf
          # Cold-flash set, taken from flash_args rather than named here —
          # see "Never hand-write the image list" below.
          mkdir -p coldflash
          cp build/flash_args coldflash/
          awk '$1 ~ /^0x/ {print
Read more
Ships withembedded-ai-harness

Spec to silicon, hands off.

Get the whole plugin
Stats
166
Stars
53
Forks
Active
Maintenance
Python
Language
MIT
License
7d ago
Last commit
6mo ago
Created

Repo: SensorsIot/Embedded-AI-Harness

Other skills on embedded-ai-harness.