Scaffold go
Cross-platform dotfiles managed by Chezmoi with Homebrew/apt and per-language version managers. One-command bootstrap for macOS and Linux with Neovim, Tmux, Zsh, and AI agent skills.
npx -y skills add urmzd/dotfiles --skill scaffold-goAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Scaffold a complete Go project with CI/CD, release pipeline, Makefile, sr.yaml, .envrc, and standard files. Uses go toolchain and make as the native build system. Loads on top of scaffold-project (run that first for cross-language standard files). Use when creating a new Go CLI, service, or module, or when the user mentions "new Go project", "go mod init", or "Go scaffold". Do NOT use for Rust, Python, Node, or Terraform projects; use the matching scaffold-<lang> skill.
SKILL.md
7.6 KB, ~1.9k tokens by cl100k_base, as published. Nobody here has run it
Scaffold Go Project
Generate a production-ready Go project following established CI/CD patterns. Read the scaffold-project skill first for standard files (README, AGENTS.md, LICENSE, CONTRIBUTING.md, llms.txt).
When to Use
- Creating a new Go CLI tool, HTTP service, or library module
- Adding CI/CD to an existing Go project missing workflows
- Standardizing a Go project to match org conventions
Generated Files
.github/workflows/ci.yml
name: CI
on:
pull_request:
branches: [main]
workflow_call:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
fmt:
name: Format
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Check formatting
run: |
unformatted=$(gofmt -l .)
if [ -n "$unformatted" ]; then
echo "The following files are not formatted:"
echo "$unformatted"
exit 1
fi
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
- uses: golangci/golangci-lint-action@v7
test:
name: Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
- run: go test ./...
.github/workflows/release.yml
name: Release
on:
push:
branches: [main]
workflow_dispatch:
concurrency:
group: release
cancel-in-progress: false
permissions:
contents: write
jobs:
ci:
if: github.actor != 'sr[bot]'
uses: ./.github/workflows/ci.yml
release:
needs: ci
runs-on: ubuntu-latest
steps:
- name: Generate app token
id: app-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.SR_RELEASER_APP_ID }}
private-key: ${{ secrets.SR_RELEASER_PRIVATE_KEY }}
repositories: ${{ github.event.repository.name }}
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ steps.app-token.outputs.token }}
- uses: urmzd/sr@v8
id: sr
with:
github-token: ${{ steps.app-token.outputs.token }}
outputs:
released: ${{ steps.sr.outputs.released }}
tag: ${{ steps.sr.outputs.tag }}
version: ${{ steps.sr.outputs.version }}
build:
needs: release
if: needs.release.outputs.released == 'true'
name: Build (${{ matrix.goos }}/${{ matrix.goarch }})
runs-on: ${{ matrix.runner }}
permissions:
contents: write
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
strategy:
fail-fast: true
matrix:
include:
- goos: linux
goarch: amd64
runner: ubuntu-latest
artifact_suffix: -linux-amd64
- goos: linux
goarch: arm64
runner: ubuntu-latest
artifact_suffix: -linux-arm64
- goos: darwin
goarch: amd64
runner: macos-15-intel
artifact_suffix: -darwin-amd64
- goos: darwin
goarch: arm64
runner: macos-15
artifact_suffix: -darwin-arm64
- goos: windows
goarch: amd64
runner: windows-latest
artifact_suffix: -windows-amd64.exe
steps:
- uses: actions/checkout@v4
with:
ref: ${{ needs.release.outputs.tag }}
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Build static binary
shell: bash
env:
GOOS: ${{ matrix.goos }}
GOARCH: ${{ matrix.goarch }}
CGO_ENABLED: "0"
run: |
BIN_NAME="${{ github.event.repository.name }}"
go build -trimpath \
-ldflags "-X main.version=${{ needs.release.outputs.version }} -X main.commit=${{ github.sha }} -X main.date=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
-o "build/bin/${BIN_NAME}${{ matrix.artifact_suffix }}" ./cmd/${BIN_NAME}
- name: Upload to release
shell: bash
run: |
BIN_NAME="${{ github.event.repository.name }}"
gh release upload "${{ needs.release.outputs.tag }}" "build/bin/${BIN_NAME}${{ matrix.artifact_suffix }}" --clobber
sr.yaml
Generate with sr init. Go uses git tags only, so packages need no version_files or stage_files:
git:
tag_prefix: "v"
floating_tag: true
v0_protection: true
commit:
types:
minor: [feat]
patch: [fix, perf, refactor]
none: [docs, revert, chore, ci, test, build, style]
changelog:
file: CHANGELOG.md
groups:
- { name: breaking, content: [breaking] }
- { name: features, content: [feat] }
- { name: bug-fixes, content: [fix] }
- { name: performance, content: [perf] }
- { name: misc, content: [chore, ci, test, build, style] }
channels:
default: stable
branch: main
content:
- name: stable
packages:
- path: .
publish:
type: go # no-op; Go modules publish via the git tag sr already cuts
See sync-release for the full schema and sr migrate for upgrading from older versions.
Makefile
.PHONY: all init build test lint fmt check run install record
MOD := $(shell basename $(CURDIR))
CMD := cmd/$(MOD)
all: check
init:
git config core.hooksPath .githooks
go mod download && go mod tidy
build:
CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o bin/$(MOD) ./$(CMD)
test:
go test ./...
lint:
golangci-lint run
fmt:
gofmt -w .
check: fmt lint test
run: build
./bin/$(MOD)
install:
CGO_ENABLED=0 go install -trimpath -ldflags="-s -w" ./$(CMD)
record:
teasr showme
For complex projects (multi-service repos, code generation, protobuf), add a justfile to handle orchestration that Make handles poorly (dependency ordering, parameterized recipes).
.envrc
# go.mod is the version pin; toolchain is system-installed via brew/apt.
PATH_add bin
Project Layout
cmd/<project-name>/ # main package (entry point)
main.go
internal/ # private packages
pkg/ # public packages (if library)
go.mod
go.sum
Gotchas
- Always use
go-version-file: go.modinstead of hardcoding Go versions CGO_ENABLED=0for static binaries. Required for pure-Go projects, especially those usingmodernc.org/sqlite- Inject version/commit/date via
-ldflags "-X main.version=...". Declarevar version, commit, date stringin main.go - No
version_filesin sr.yaml. Go versioning is tag-only golangci-lint-action@v7auto-detects Go version from go.mod- Bot skip uses
github.actor != 'github-actions[bot]'or'sr[bot]'depending on which bot triggers - Cross-compilation is native in Go; no
crosstool needed, just setGOOS/GOARCH
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.