Hadolint Dockerfile Security Linting
AgentSecOps/SecOpsAgentKit
Lints Dockerfiles with Hadolint for security misconfigurations and best-practice violations, locally and in CI, with strict, balanced and permissive rule templates.
A skill your agent uses when writing, reviewing, testing, or shipping Go code and HTTP services: idioms, %w error wrapping, goroutine/context/errgroup concurrency, net/http 1.22 routing, log/slog…
$ npx skills add ericrisco/rsc-harness --skill go -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install ericrisco/rsc-harness go --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/ericrisco/rsc-harness.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/go .claude/skills/go && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "go" agent skill from https://github.com/ericrisco/rsc-harness/tree/main/skills/go into .claude/skills/go/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "go", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/ericrisco/rsc-harness/tree/main/skills/goType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add ericrisco/rsc-harness --skill go -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install ericrisco/rsc-harness go --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ericrisco/rsc-harness.git skills-src && mkdir -p .agents/skills && cp -r skills-src/skills/go .agents/skills/go && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "go" agent skill from https://github.com/ericrisco/rsc-harness/tree/main/skills/go into .agents/skills/go/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "go", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add ericrisco/rsc-harness --skill go -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install ericrisco/rsc-harness go --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ericrisco/rsc-harness.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/skills/go .cursor/skills/go && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "go" agent skill from https://github.com/ericrisco/rsc-harness/tree/main/skills/go into .cursor/skills/go/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "go", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/ericrisco/rsc-harness.git --path skills/go--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add ericrisco/rsc-harness --skill go -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install ericrisco/rsc-harness go --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ericrisco/rsc-harness.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/skills/go .gemini/skills/go && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "go" agent skill from https://github.com/ericrisco/rsc-harness/tree/main/skills/go into .gemini/skills/go/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "go", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install ericrisco/rsc-harness goInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add ericrisco/rsc-harness --skill go -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/ericrisco/rsc-harness.git skills-src && mkdir -p .github/skills && cp -r skills-src/skills/go .github/skills/go && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "go" agent skill from https://github.com/ericrisco/rsc-harness/tree/main/skills/go into .github/skills/go/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "go", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add ericrisco/rsc-harness --skill go -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install ericrisco/rsc-harness go --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ericrisco/rsc-harness.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/skills/go .opencode/skills/go && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "go" agent skill from https://github.com/ericrisco/rsc-harness/tree/main/skills/go into .opencode/skills/go/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "go", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
goA skill your agent uses when writing, reviewing, testing, or shipping Go code and HTTP services: idioms, %w error wrapping, goroutine/context/errgroup concurrency, net/http 1.22 routing, log/slog…
Go is an agent skill from ericrisco/rsc-harness. Use when writing, reviewing, testing, or shipping Go code and HTTP services: idioms, %w error wrapping, goroutine/context/errgroup concurrency, net/http 1.22 routing, log/slog, project layout, table-driven tests, Go hardening. NOT language-agnostic threat modeling (that is secure-coding), NOT Dockerfile/CI shipping (that is deployment).
Its SKILL.md is about 3.9k tokens, which your agent loads only when the skill is triggered. The skill folder holds 9 other files, including scripts and reference files (for example `evals/README.md`, `evals/cases.yaml` and `references/concurrency.md`).
It sits in Security, covering Async programming, Secure coding and Threat modeling. It works with Docker. The repository describes itself as: Your agent invents things because it has no memory, and can't touch your database because it has no arms. rsc is the meta-harness that gives it both, plus the trade to know the… The licence is MIT.
Read from SKILL.md and the folder at commit e3d5b33. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Ships 1 file in scripts/ (Shell), which the agent can run.
Shell commands in SKILL.md call:
gogitFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md. Its commands use git, which can reach the network depending on how they are called.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Go loads about 3.9k tokens when it runs, and up to ~14k if it reads all its reference files. Until then it costs about 87 tokens; SKILL.md has 1,178 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); the scripts in this folder are not scanned.
The full file from ericrisco/rsc-harness at commit e3d5b33, republished under its MIT licence (© ericrisco). 1,178 words, ~3,871 tokens.
.claude/skills/go/SKILL.md (or your agent's skills folder). This skill also uses 6 other files; get the full folder from GitHub.Targets Go 1.22+ (Go 1.26 is the current stable release): enhanced net/http routing
(mux.HandleFunc("GET /users/{id}", h) + r.PathValue), log/slog structured
logging, and fixed loop-variable semantics (no more tt := tt).
⚠️ SDD new-feature gate — read this first. If this skill fired on a new, non-trivial feature or behaviour change and there is no approved spec + plan under
02-DOCS/wiki/sdd/, STOP — do not write feature code yet. Hand off to../specify/SKILL.mdfirst: it runs brainstorm → spec → plan → tasks before any code, then routes back here once the plan is approved. Build here directly only for a genuinely one-line / low-risk change. Method:../sdd/SKILL.md.
Go error handling and HTTP contract design (status-code taxonomy, REST resource naming) live here — this skill is the canonical authority for both in Go. Delegate outward:
secure-coding. This skill keeps the Go-specific controls:
SQL params, server timeouts, govulncheck, TLS defaults.deployment.
This skill ships only a Docker note + ldflags.harness
(see "Project grounding" below).Non-service Go (CLI tooling, codegen, ML): the patterns apply, but the HTTP/production half is irrelevant.
Useful zero value. Design types so the zero value works before any constructor.
// Good: zero-value Counter is ready; the zero-value mutex is unlocked. var b bytes.Buffer too.
type Counter struct {
mu sync.Mutex
n int
}
func (c *Counter) Inc() { c.mu.Lock(); c.n++; c.mu.Unlock() }
// Bad: nil map field panics on first write (assignment to entry in nil map); hidden init step.
type Registry struct{ items map[string]int }
func (r *Registry) Add(k string) { r.items[k]++ } // panic if items was never make()'dAccept interfaces, return structs. Return the concrete type; declare the interface where it is consumed.
type UserStore interface { // declared in package service - only what it needs
GetUser(ctx context.Context, id string) (*User, error)
}
func NewService(s UserStore) *Service { return &Service{store: s} } // Good: return *Service
// Bad: func NewService(s UserStore) UserStore - returning the interface hides the type.Functional options. Defaults first, then apply options.
type Server struct {
addr string
timeout time.Duration
logger *slog.Logger
}
type Option func(*Server)
func WithTimeout(d time.Duration) Option { return func(s *Server) { s.timeout = d } }
func WithLogger(l *slog.Logger) Option { return func(s *Server) { s.logger = l } }
func NewServer(addr string, opts ...Option) *Server {
s := &Server{addr: addr, timeout: 30 * time.Second, logger: slog.Default()} // defaults first
for _, opt := range opts {
opt(s)
}
return s
}Use a plain Config struct once options exceed ~5; options are for optional, composable
tuning, not required fields.
Embedding for composition. Embed to borrow a behavior, not to fake inheritance.
// Good: the service gets .Info/.Error for free from the embedded logger.
type Service struct {
*slog.Logger
store UserStore
}
// Bad: deep type trees (Base -> Middle -> Leaf) modeling "is-a" inheritance - avoid.Early return. Clear over clever: invert the error and return; keep the happy path flat
(no arrow code).
// Good: each failure returns immediately; the success path is unindented.
func save(ctx context.Context, u *User) error {
if u == nil {
return errors.New("nil user")
}
if err := validate(u); err != nil {
return fmt.Errorf("validate: %w", err)
}
return store.Put(ctx, u)
}
// Bad: if u != nil { if err := validate(u); err == nil { ... } else { ... } } - arrow code.No package-level mutable state. Inject via constructor (func New(db *sql.DB) *Server),
never a global var db *sql.DB opened in init() - globals couple everything and kill
testability.
Receivers. Pick value or pointer per type and stay consistent across its method set;
mutating / large / contains-sync -> pointer.
Go 1.22 loopvar. Loop variables are per-iteration now. Stop emitting the workaround:
inside for _, tt := range tests the line // tt := tt is obsolete - DELETE it.
Sentinel vs typed. Sentinels for identity; typed errors for data.
var ErrNotFound = errors.New("not found") // sentinel: identity
type ValidationError struct{ Field, Msg string } // typed: carries data
func (e *ValidationError) Error() string { return fmt.Sprintf("%s: %s", e.Field, e.Msg) }Wrap and classify. Wrap every crossed boundary with %w; never compare message strings.
err := fmt.Errorf("find user %s: %w", id, ErrNotFound)
if errors.Is(err, ErrNotFound) { /* sentinel match through the wrap chain */ }
var verr *ValidationError
if errors.As(err, &verr) { /* typed match: verr.Field, verr.Msg */ }
joined := errors.Join(err1, err2) // 1.20+: aggregate; Is/As traverse both3-layer boundary (the canonical flow). Repo wraps the driver sentinel into a domain sentinel; service passes it through; handler classifies once and maps to a status, logging only the unexpected.
// repository: translate sql.ErrNoRows into a domain sentinel, keep the chain.
func (r *Repo) GetUser(ctx context.Context, id string) (*User, error) {
var u User
err := r.db.QueryRowContext(ctx, "SELECT id, name FROM users WHERE id = $1", id).
Scan(&u.ID, &u.Name)
if errors.Is(err, sql.ErrNoRows) {
return nil, fmt.Errorf("user %s: %w", id, ErrNotFound)
}
if err != nil {
return nil, fmt.Errorf("query user %s: %w", id, err)
}
return &u, nil
}
// handler: classify once, map to HTTP status.
func (h *Handler) getUser(w http.ResponseWriter, r *http.Request) {
u, err := h.svc.GetUser(r.Context(), r.PathValue("id"))
switch {
case err == nil:
writeJSON(w, http.StatusOK, u)
case errors.Is(err, ErrNotFound):
http.Error(w, "not found", http.StatusNotFound)
default:
slog.Error("get user", "err", err)
http.Error(w, "internal error", http.StatusInternalServerError)
}
}Full handler adapter (error-returning apiHandler) -> references/http-services.md.
defer + named return to capture Close() errors:
func read(name string) (err error) {
f, e := os.Open(name)
if e != nil {
return e
}
defer func() { err = errors.Join(err, f.Close()) }() // capture Close() into the return
return nil
}context.Context is the first param of every call, never stored in a struct, never nil
(use context.TODO() while wiring). Bound work with a context deadline; bound concurrency
with errgroup — the derived ctx cancels siblings on first error, and g.SetLimit(n) caps
in-flight goroutines:
g, ctx := errgroup.WithContext(ctx)
g.SetLimit(8)
for _, id := range ids {
g.Go(func() error { return process(ctx, id) }) // Go 1.22+: no id := id needed
}
err := g.Wait()Three rules cover most service code: every goroutine needs a known exit path (a started
goroutine you cannot stop is a leak); an unbuffered ch <- v with no receiver after a cancel
blocks forever, so buffer it and select on ctx.Done(); run -race in CI. Low-level
needs map to sync.Once (lazy init), sync.RWMutex (read-heavy state), sync/atomic
(atomic.Int64 counters).
Full implementations — context plumbing, channel/select patterns, leak detection, worker
pools, pipelines, fan-in/out, semaphores, singleflight, and a withRetry helper (backoff +
full jitter, ctx-aware, never retries 4xx) -> references/concurrency.md.
Go 1.22 routed mux — method and path live in the pattern; the error-returning adapter
centralizes status mapping:
mux := http.NewServeMux()
mux.HandleFunc("GET /users/{id}", getUser) // 405 on wrong method, 404 on no match
id := r.PathValue("id") // inside the handler
type apiHandler func(http.ResponseWriter, *http.Request) error
func (h apiHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if err := h(w, r); err != nil { /* classify via errors.Is/As -> status + slog */ }
}Set all four http.Server timeouts (ReadHeaderTimeout, ReadTimeout, WriteTimeout,
IdleTimeout) — an unbounded read is a Slowloris DoS. Graceful shutdown on signal:
signal.NotifyContext(ctx, os.Interrupt, syscall.SIGTERM), then srv.Shutdown(shutdownCtx)
on <-ctx.Done().
Routing patterns, chi vs stdlib, the full middleware chain (request-id, slog, panic-recovery,
timeout), config, timeout values, functional-options server, and JSON helpers ->
references/http-services.md.
cmd/api/main.go # entrypoint: wiring only
internal/handler/ # HTTP adapters
internal/service/ # business logic; defines the interfaces it needs
internal/repository/ # data access (pgx); implements service interfaces
internal/config/ # env parsing, validation
pkg/ # ONLY genuinely reusable, stable public API
testdata/ # fixtures, golden files
go.mod go.sumWire the layers with constructor injection, outermost depends inward:
repo := repository.New(db); svc := service.New(repo); h := handler.New(svc).
Package naming: short, lowercase, no underscores, no util/common, avoid stutter
(user.User, not user.UserStruct). Interfaces live on the consumer side: the
service package declares UserStore; the repository package implements it without
importing the interface.
Table-driven with subtests and parallelism:
func TestParse(t *testing.T) {
tests := []struct {
name string
in string
wantErr error
}{
{"ok", "42", nil},
{"bad", "x", ErrInvalid},
}
for _, tt := range tests { // Go 1.22+: no tt := tt needed
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
_, err := Parse(tt.in)
if !errors.Is(err, tt.wantErr) { // classify, not just != nil
t.Fatalf("got %v, want %v", err, tt.wantErr)
}
})
}
}HTTP handlers via httptest: req := httptest.NewRequest("GET", "/users/1", nil);
w := httptest.NewRecorder(); h.ServeHTTP(w, req); then assert on w.Code / w.Body.
Use t.Helper() in assertions, t.TempDir() for files, t.Cleanup() for teardown,
t.Setenv() for env. Run go test -race -cover ./..., and treat go vet / staticcheck
failures as build failures. Stdlib testing is the default; reach for testify/require only
for deep-equality or large suites.
Golden files, fuzzing, benchmarks, httptest matrices, interface fakes ->
references/testing.md.
Validate at the boundary: parametrize SQL (PostgreSQL; prefer pgx v5 over database/sql);
cap request bodies and reject unknown fields; set a TLS floor and trust the crypto/tls
defaults:
// Good // Bad: string interpolation = SQL injection.
db.QueryContext(ctx, "... WHERE id = $1", id) // db.QueryContext(ctx, fmt.Sprintf("... '%s'", id))
r.Body = http.MaxBytesReader(w, r.Body, 1<<20) // 1 MiB cap
dec := json.NewDecoder(r.Body)
dec.DisallowUnknownFields()
tlsCfg := &tls.Config{MinVersion: tls.VersionTLS12} // do not hand-pick cipher suitesServer timeouts are a DoS control - set all four (see HTTP services above).
Run govulncheck ./... in CI; keep deps honest with go mod tidy + go mod verify. Read
secrets from env / a secret manager, never log them; redact tokens with slog ReplaceAttr.
Deeper authz/abuse review -> secure-coding.
Wire log/slog JSON in main (level from env), then slog.SetDefault:
logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: lvl}))
slog.SetDefault(logger)Stamp the version with ldflags and read module info at runtime:
go build -ldflags "-X main.version=$(git describe --tags --always)" ./cmd/api
# at runtime: if info, ok := debug.ReadBuildInfo(); ok { slog.Info("build", "go", info.GoVersion) }Mount net/http/pprof on a separate internal mux/port (never the public listener);
expose /healthz (static 200 liveness) and /readyz (calls db.PingContext with a short
timeout, 503 on failure). Graceful shutdown as shown above.
Docker note: distroless/static base, CGO_ENABLED=0, multi-stage build. Full Containerfile
-> deployment.
| Anti-pattern | Do instead |
|---|---|
Storing ctx in a struct to avoid threading it | ctx is the first arg of every call. |
_ = err because it "can't fail" | Handle, log, or document why; errcheck catches it. |
| String-comparing the error message | errors.Is / errors.As; messages are not API. |
Global db / logger because it's "simpler" | Inject via constructor; globals kill testability. |
| Fire-and-forget goroutine ("it'll finish") | Unbounded/unstoppable goroutine = leak; give it ctx + buffer. |
tt := tt added "to be safe" | Go 1.22 fixed loopvar; it's noise now. |
| Interface in the provider package, returning the interface | Return structs; interface lives with the consumer. |
| No timeouts because "the LB handles it" | Set all four http.Server timeouts; Slowloris is real. |
panic on bad input | Return an error; panic only for programmer bugs / main wiring. |
Skipping -race because tests pass | Race bugs are silent; -race in CI is mandatory. |
fmt.Sprintf into SQL on "trusted" input | Parametrize ($1...); trust nothing at the boundary. |
testify everywhere | Stdlib first; reach for testify only when it earns its weight. |
| Task | Command |
|---|---|
| Format | gofmt -w . / goimports -w . |
| Vet | go vet ./... |
| Lint | staticcheck ./... / golangci-lint run |
| Test (race+cover) | go test -race -cover ./... |
| Fuzz | go test -fuzz=Fuzz -fuzztime=30s |
| Vulns | govulncheck ./... |
| Local gate | ./scripts/verify.sh (run in your module root) |
In a project with a 02-DOCS/ layer (the harness Karpathy wiki), this
project's service decisions live in 02-DOCS/wiki/stack/go.md, indexed from
02-DOCS/wiki/index.md (the Knowledge map; root CLAUDE.md keeps only a short pointer to it).
Read it first on every use and stay consistent. If it is missing or stale, write the project's
real choices there — the project layout, the router (stdlib 1.22 / chi), the error and slog
conventions, concurrency/timeout defaults — index it, and bump its Updated date in the same
change.
No 02-DOCS/ layer? Skip silently (optionally suggest harness). Unlike the brand study,
technical conventions are recorded, not gated — never block the task on this.
© ericrisco, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 6 other files (scripts, references) in skills/go of ericrisco/rsc-harness.
Open the folder on GitHubat commit e3d5b33
Go next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Go this skillericrisco/rsc-harness | 167 | — | ~3.9k | Automated safety check: Pass | MIT | |
| Hadolint Dockerfile Security LintingAgentSecOps/SecOpsAgentKit | 220 | 1 repos | ~4.4k | Automated safety check: Pass | Custom licence | |
| Code Securitysemgrep/skills | 322 | — | ~1.2k | Automated safety check: Pass | Custom licence | |
| Implementing Container Image Minimal Base With Distrolessmukul975/Anthropic-Cybersecurity-Skills | 34k | — | ~1.7k | Automated safety check: Pass | Apache-2.0 | |
| Code Audit3stoneBrother/code-audit | 893 | 1 repos | ~2.7k | Automated safety check: Pass | None | |
| Cb Security HardeningBlkLeg/CircuitBreaker | 201 | — | ~2.1k | Automated safety check: Pass | MIT |
AgentSecOps/SecOpsAgentKit
Lints Dockerfiles with Hadolint for security misconfigurations and best-practice violations, locally and in CI, with strict, balanced and permissive rule templates.
semgrep/skills
Security guidelines for writing secure code. An agent skill from semgrep/skills.
mukul975/Anthropic-Cybersecurity-Skills
Reduces container attack surface by building application images on Google distroless base images that ship only the application runtime - no shell, package manager, or OS utilities - using…
3stoneBrother/code-audit
Professional code security audit skill covering 55+ vulnerability types.
BlkLeg/CircuitBreaker
Enforces Circuit Breaker security hardening conventions across backend, frontend, Docker, and nginx.
TheDecipherist/claude-code-mastery-project-starter-kit
Node.js backend runtime and process-lifecycle rules that Claude reliably gets wrong.
ericrisco/rsc-harness
A skill your agent uses when designing or analyzing a controlled experiment — falsifiable hypothesis, sample size from an MDE, reading significance/CI/power, CUPED, or rescuing tests that won't go…
ericrisco/rsc-harness
A skill your agent uses when making a web UI conform to WCAG 2.2 Level AA — axe-core or Lighthouse a11y violations, keyboard operability, focus management, ARIA roles/names/live regions, contrast…
ericrisco/rsc-harness
A skill your agent uses when running or fixing paid acquisition on Google or Meta — campaign structure (Performance Max, Demand Gen, Search, Advantage+), platform-fit creative, budget/scaling rules…
ericrisco/rsc-harness
A skill your agent uses when measuring whether an LLM or agent system actually got better and gating merges on it: golden sets, fixing an inflated LLM-as-judge, scoring RAG (faithfulness, contextual…
ericrisco/rsc-harness
A skill your agent uses when a creative goal must become a finished media file: pick and order generative-media models per modality — AI voiceover, image-to-video clips, score — then glue them with…
ericrisco/rsc-harness
A skill your agent uses when instrumenting product or web analytics — GA4/PostHog SDK wiring, event taxonomy, funnels, double-counted events, consent gating, PII scrubbing.
Works with
Categories
A skill your agent uses when writing, reviewing, testing, or shipping Go code and HTTP services: idioms, %w error wrapping, goroutine/context/errgroup concurrency, net/http 1.22 routing, log/slog…. Go is an agent skill from ericrisco/rsc-harness.22 routing, log/slog, project layout, table-driven tests, Go hardening.
Go fits situations like: shipping Go code and HTTP services: idioms; %w error wrapping; goroutine/context/errgroup concurrency; net/http 1.22 routing.
Run `npx skills add ericrisco/rsc-harness --skill go -a claude-code`. Or copy the skill folder (skills/go in ericrisco/rsc-harness) into .claude/skills/go in your project. Claude Code loads it when a task matches its description.
Run `npx skills add ericrisco/rsc-harness --skill go -a codex`. Or copy the skill folder (skills/go in ericrisco/rsc-harness) into .agents/skills/go in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add ericrisco/rsc-harness --skill go -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/go, .gemini/skills/go, .github/skills/go and .opencode/skills/go in your project.
Going by SKILL.md and its folder, Go needs a shell for the scripts in its folder and the command-line tools its instructions call (go and git). Our summary lists: A Bash shell; Docker.
SKILL.md contains no URLs. Its commands use git, which can reach the network depending on how they are called. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. The check reads SKILL.md only: the scripts in the folder are not scanned, so read them before running anything.
Go is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 3.9k tokens (SKILL.md is roughly 15k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 10k tokens, read only when the agent opens those files.
Skills that share tags, products or a category with Go: Hadolint Dockerfile Security Linting (AgentSecOps/SecOpsAgentKit, 220 stars), Code Security (semgrep/skills, 322 stars), Implementing Container Image Minimal Base With Distroless (mukul975/Anthropic-Cybersecurity-Skills, 34k stars) and Code Audit (3stoneBrother/code-audit, 893 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
ericrisco (a GitHub user) maintains it in ericrisco/rsc-harness, which has 167 GitHub stars. The repository holds 227 skills in this directory. The repository was last updated on October 7, 2026.
Source: ericrisco/rsc-harness on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.