
Golang Safety
Install this when you want your Go agent to catch nil panics, slice aliasing, and numeric pitfalls before they ship as silent corruption.
Overview
golang-safety is an agent skill most often used in Ship review (also Build backend, Operate errors) that enforces defensive Go patterns to prevent panics, silent corruption, and subtle runtime bugs.
Install
npx skills add https://github.com/samber/cc-skills-golang --skill golang-safetyWhat is this skill?
- Persona: defensive Go engineer treating untested nil and capacity assumptions as latent crashes
- Covers nil panics, append aliasing, concurrent map access, float comparison, and zero-value design
- Safe type assertions (comma-ok) and Go 1.25+ reflect.TypeAssert guidance for reflection paths
- Resource lifecycle: defer in loops, defensive copying of slices and maps
- Uses Read/Edit/Write plus go and golangci-lint bash tooling for grounded fixes
Adoption & trust: 3.8k installs on skills.sh; 2k GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
Your Go code runs in production until a nil dereference, shared slice mutation, or overflow turns a happy path into a crash or wrong data without a clear audit trail.
Who is it for?
Solo builders maintaining Go APIs, workers, or CLIs who want agent-guided nil-safety and concurrency foot-gun fixes during review or incident triage.
Skip if: Teams that only need threat-modeling or OWASP-style hardening without day-to-day Go correctness, or repos that are not Go.
When should I use this skill?
Encountering nil panics, append aliasing, map concurrent access, float comparison pitfalls, zero-value design questions, or when reviewing for nil-safety, numeric overflow, defer in loops, and defensive slice/map copies.
What do I get? / Deliverables
After the skill runs, risky patterns get explicit guards, copies, and idiomatic fixes so normal code paths fail loudly at compile time or safely at runtime instead of corrupting state.
- Reviewed or patched Go source with defensive patterns applied
- Inline explanations of nil, aliasing, and lifecycle risks addressed
Recommended Skills
Journey fit
Spans multiple journey phases - primary shelf plus alternate fits below.
Canonical shelf is Ship/review because the skill is framed as defensive review and panic prevention right before or after implementation changes. Review is where nil-safety, defer-in-loop, and map concurrency checks belong in the solo-builder journey—not only while typing the first handler.
Where it fits
Hardent a new HTTP handler before merge by checking nil receivers and safe conversions on query params.
Walk a PR for append aliasing and map writes without mutexes before tagging a release.
Trace a production panic to a defer inside a range loop and apply the loop-scoped defer pattern.
Align table-driven tests with zero-value expectations so regressions surface before deploy.
How it compares
Use as a procedural correctness checker alongside golangci-lint—not as a substitute for dependency or supply-chain security skills.
Common Questions / FAQ
Who is golang-safety for?
Indie and solo developers using AI coding agents on Go backends, CLIs, and services who keep hitting panics, data races on maps, or subtle slice aliasing bugs.
When should I use golang-safety?
During Build when implementing handlers and structs; during Ship review before merge; during Operate when stack traces point to nil, defer-in-loop, or conversion overflow.
Is golang-safety safe to install?
It is an MIT-licensed skill that can edit files and run go/golangci-lint via the agent—review the Security Audits panel on this Prism page and your repo policies before enabling bash tools.
SKILL.md
READMESKILL.md - Golang Safety
**Persona:** You are a defensive Go engineer. You treat every untested assumption about nil, capacity, and numeric range as a latent crash waiting to happen. # Go Safety: Correctness & Defensive Coding Prevents programmer mistakes — bugs, panics, and silent data corruption in normal (non-adversarial) code. Security handles attackers; safety handles ourselves. ## Best Practices Summary 1. **Prefer generics over `any`** when the type set is known — compiler catches mismatches instead of runtime panics 2. **Always use safe type assertions** — for normal interfaces use comma-ok (`v, ok := x.(T)`); for reflection in Go 1.25+ prefer `reflect.TypeAssert[T](value)` over `value.Interface().(T)`. 3. **Typed nil pointer in an interface is not `== nil`** — the type descriptor makes it non-nil 4. **Writing to a nil map panics** — always initialize before use 5. **`append` may reuse the backing array** — both slices share memory if capacity allows, silently corrupting each other 6. **Return defensive copies** from exported functions — otherwise callers mutate your internals 7. **`defer` runs at function exit, not loop iteration** — extract loop body to a function 8. **Integer conversions truncate silently** — `int64` to `int32` wraps without error 9. **Float arithmetic is not exact** — use epsilon comparison or `math/big` 10. **Design useful zero values** — nil map fields panic on first write; use lazy init 11. **Use `sync.Once` for lazy init** — guarantees exactly-once even under concurrency ## Nil Safety Nil-related panics are the most common crash in Go. ### The nil interface trap Interfaces store (type, value). An interface is `nil` only when both are nil. Returning a typed nil pointer sets the type descriptor, making it non-nil: ```go // ✗ Dangerous — interface{type: *MyHandler, value: nil} is not == nil func getHandler() http.Handler { var h *MyHandler // nil pointer if !enabled { return h // interface{type: *MyHandler, value: nil} != nil } return h } // ✓ Good — return nil explicitly func getHandler() http.Handler { if !enabled { return nil // interface{type: nil, value: nil} == nil } return &MyHandler{} } ``` ### Nil map, slice, and channel behavior | Type | Index into nil | Write to nil | Len/Cap of nil | Range over nil | | --- | --- | --- | --- | --- | | Map | Zero value | **panic** | 0 | 0 iterations | | Slice | **panic** | **panic** | 0 | 0 iterations | | Channel | Blocks forever | Blocks forever | 0 | Blocks forever | ```go // ✗ Bad — nil map panics on write var m map[string]int m["key"] = 1 // ✓ Good — initialize or lazy-init in methods m := make(map[string]int) func (r *Registry) Add(name string, val int) { if r.items == nil { r.items = make(map[string]int) } r.items[name] = val } ``` See **[Nil Safety Deep Dive](./references/nil-safety.md)** for nil receivers, nil in generics, and nil interface performance. ## Slice & Map Safety ### Slice aliasing — the append trap `append` reuses the backing array if capacity allows. Both slices then share memory: ```go // ✗ Dangerous — a and b share backing array a := make([]int, 3, 5) b := app