AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Go Style

skill-bitwise-media-group-skills-go-style · by bitwise-media-group

Modern Go code style for stdlib-first programs — error wrapping with %w, sentinel errors, structured logging with log/slog, context threading, consumer-defined interfaces, nil-safe constructors, net/http servers with method-pattern routing, flag/env configuration for services, and cobra commands with viper configuration for CLI tools. Use when writing, reviewing, or refactoring any Go code (.go f…

No reviews yet
0 installs
20 views
0.0% view→install

Install

$ agentstack add skill-bitwise-media-group-skills-go-style

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-bitwise-media-group-skills-go-style)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
23d ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Go Style? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Go style conventions

Stdlib-first conventions for modern Go (1.22+). Apply them to new code and match them when editing existing code; reach for a third-party dependency only when the standard library genuinely cannot do the job. For the rationale behind each rule and extended examples, see [reference.md](reference.md).

1. Wrap errors with %w and the failing operation, exactly once

Name the operation lowercase, no "failed to", no trailing punctuation. Wrap where context is added; pass through errors that are already contextual:

if err := v.BindPFlags(fs); err != nil {
	return nil, fmt.Errorf("bind flags: %w", err)
}
if err := cfg.Validate(); err != nil {
	return nil, err // Validate's message already says what failed — don't double-wrap
}

%w keeps the chain inspectable with errors.Is/errors.As; a %v wrap severs it.

2. Sentinel errors for conditions callers branch on

Declare package-level sentinels with errors.New; expose structured failures as error types. Callers match with errors.Is (sentinels) or errors.As (types) — never by comparing message strings.

var ErrUnknownClient = errors.New("unknown client")

3. Log with log/slog, structured and context-aware

log/slog only — no log.Printf, no third-party loggers. Pass the request context so handlers bridged to tracing can correlate, and attach the error as an attribute:

log.LogAttrs(r.Context(), slog.LevelError, "client map load error", slog.Any("error", err))

main builds one JSON-handler logger writing to stdout; everything else receives a *slog.Logger — never a package-level global.

4. Thread context.Context; never store it

ctx context.Context is the first parameter of any function that does I/O, blocks, or logs. Derive the root context from process signals in main and hand it down:

ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()

Never keep a context in a struct field — storing it freezes cancellation at construction time.

5. Define interfaces at the consumer, and keep them small

The package that calls a dependency declares the interface it needs — one or two methods — and producers return concrete types. Tests then substitute a hand-written fake (see the go-testing skill):

// Minter turns a (service account, scopes) request into an access token.
type Minter interface {
	Mint(ctx context.Context, saEmail string, scopes []string) (token string, expiresIn int64, err error)
}

6. Constructors tolerate nil dependencies

NewX(...) constructors substitute no-ops for optional dependencies so call sites and tests stay terse:

func NewBroker(loader *clientmap.Loader, minter token.Minter, log *slog.Logger) *Broker {
	if log == nil {
		log = slog.New(slog.DiscardHandler)
	}
	return &Broker{loader: loader, minter: minter, log: log}
}

7. Serve HTTP with the stdlib

net/http and http.NewServeMux with method patterns (Go 1.22+) — no router frameworks. Middleware is func(http.Handler) http.Handler; wrap the response writer to record status, and keep health probes out of request logs:

mux := http.NewServeMux()
mux.HandleFunc("POST /token", b.handleToken)
mux.HandleFunc("GET /healthz", health)

8. Configuration: flag > env > default

Every flag has a matching environment variable — the flag name upper-cased, dashes as underscores (--client-map-uriCLIENT_MAP_URI). Parse into one Config struct, validate it once at startup, and fail fast with a wrapped error. For a service or single-purpose binary the stdlib flag package with os.LookupEnv fallbacks is enough.

9. CLI tools: cobra commands, viper configuration

A program that exposes subcommands is a CLI tool — build its command tree with github.com/spf13/cobra and bind configuration with github.com/spf13/viper, keeping the flag > env > default precedence from rule 8 (viper adds config files between env and default). Commands use RunE and return errors — main stays the only place that exits — and silence cobra's noise on real failures:

root := &cobra.Command{
	Use:           "myapp",
	Short:         "One line on what the tool does.",
	SilenceUsage:  true, // errors are failures, not usage mistakes
	SilenceErrors: true, // main logs the error once
}
v.SetEnvPrefix("MYAPP")
v.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
v.AutomaticEnv()
if err := v.BindPFlags(cmd.Flags()); err != nil {
	return fmt.Errorf("bind flags: %w", err)
}

Give every command a Short, a Long, and a runnable Example, and expose the root command via a Root() accessor — the go-docs skill generates the CLI reference from it. Keep business logic out of cmd packages: commands parse and validate input, then call internal/ packages.

10. Build strings with strings.Builder, never += in a loop

Strings are immutable, so each s += t allocates and copies a new string — repeated in a loop that is quadratic. Accumulate with strings.Builder and call String() once at the end:

var spec strings.Builder
for i, d := range defaults {
	if i > 0 {
		spec.WriteString(",")
	}
	spec.WriteString(d)
}
return spec.String()

The same applies inside builder writes: b.WriteString(prefix + l + "\n") allocates a temporary string every iteration just to copy it into the builder. One WriteString per piece:

for _, l := range lines {
	b.WriteString(prefix)
	b.WriteString(l)
	b.WriteString("\n")
}

When the parts are already a slice and you only need a separator, strings.Join(defaults, ",") is the one-line form of the same loop. A standalone a + b expression outside a loop is fine — the rule is about repeated appends.

11. Range over Seq iterators, not throwaway slices

When a split is consumed once by a loop, use the iterator variants (Go 1.24+) — they yield each piece as it is found instead of allocating a []string that is immediately discarded:

for w := range strings.FieldsSeq(s) {
	// ...
}

strings.SplitSeq, strings.FieldsSeq, strings.Lines, and their bytes counterparts replace Split, Fields, and manual line scanning inside range loops. Keep the slice-returning forms when you actually need the slice — its length, an index, a sort, or to pass it along.

12. Reach for slices and maps before writing the loop

A loop that scans for membership, an index, a minimum, or equality is a stdlib one-liner (Go 1.21+) — slices.Contains, slices.IndexFunc, slices.Max, slices.Equal, maps.Keys. The call states the intent; the hand-rolled loop makes the reader reverse-engineer it:

if slices.Contains(tokens, "all") {
	tokens = tokens[:0]
	for _, p := range providers {
		tokens = append(tokens, p.Name())
	}
}

The remaining loop is fine — it transforms per element. Replace loops whose entire body is a comparison; use slices.Sort/slices.SortFunc over sort.Slice for the same reason.

13. Clamp scalars with the min/max builtins, not comparison guards

The min/max builtins (Go 1.21+) return the smallest or largest of two or more ordered values — the scalar companions to slices.Min/slices.Max. An if that compares a value against a bound and overwrites it is a clamp; write the assignment it already is:

paneH := max(d.h-footerH-headerH, 3) // floor each pane dimension at its minimum
paneW := max((d.w-2)/2, 10)

not the guard it started as:

paneH := d.h - footerH - headerH
if paneH < 3 {
	paneH = 3
}

max(x, lo) floors x, min(x, hi) caps it, and min(max(x, lo), hi) clamps to a range. gopls's minmax analyzer flags the guard form.

14. Keep go fmt and go vet clean

Code is always gofmt-formatted (go fmt ./...) and passes go vet ./.... Comments state constraints and invariants the code cannot express — never what the next line does.

For tests and fuzzing see the go-testing skill; for project layout and Makefiles see the go-project skill; for releases and CI see the go-release skill; for doc comments and CLI reference generation see the go-docs skill.

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.