Source profileQuality 96/100

speakeasy-api/gram/.agents/skills/golang/SKILL.md

golang

Rules and best practices when writing and editing Go (Golang) code

Source repository stars
266
Declared platforms
0
Static risk flags
0
Last source update
2026-08-25
Source checked
2026-08-25

Decision brief

What it does: where it fits

Three problems in four lines: the comment narrates a past refactor, it defers to a comment that can move or disappear, and WriteTimeout ends up with no documentation at all.

Best for

    Not for

    • Tasks that require unconfirmed production actions or broad system permissions.
    • Environments where the pinned source and install steps cannot be inspected.

    Compatibility matrix

    Platform support, with evidence labels

    PlatformStatusEvidenceWhat to check
    CodexNot declaredNo explicit evidencePortability before use
    Claude CodeNot declaredNo explicit evidencePortability before use
    CursorNot declaredNo explicit evidencePortability before use
    Gemini CLINot declaredNo explicit evidencePortability before use
    Open the compatibility checker

    Installation

    Inspect first. Install second.

    The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

    Source-detected install commandSource
    npx skills add https://github.com/speakeasy-api/gram --skill ".agents/skills/golang"
    Safe inspection promptEditorial

    Inspect the Agent Skill "golang" from https://github.com/speakeasy-api/gram/blob/8af0601cf530721aaa686c2718d76e7990226d33/.agents/skills/golang/SKILL.md at commit 8af0601cf530721aaa686c2718d76e7990226d33. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

    Workflow

    What the source asks the agent to do

    1. 01

      Comments

      Three problems in four lines: the comment narrates a past refactor, it defers to a comment that can move or disappear, and WriteTimeout ends up with no documentation at all.

      Write comments that describe current intent and behavior. Do NOT leave "intermediate" comments narrating the edit you just made (e.g. "previously this returned X, now it returns Y", "renamed from Foo"). That commentary,…Do NOT write "see X" comments that point at a comment somewhere else (e.g. "see the note on Foo above", "see handler.go for details"). The target moves or gets rewritten and the pointer silently goes stale. The test is…Document struct fields one per field, at least on exported types. A comment placed above only the first field of a group documents just that field: go doc . and editor hovers show nothing for the rest. Grouped const and…
    2. 02

      Updating the API

      We use Goa to design our API and generate server code. All Goa code lives in server/design. The Goa DSL is documented in https://pkg.go.dev/goa.design/goa/v3/dsl.

      Update the Goa design files in server/design to reflect the API change.Run mise run gen:goa-serverThis will regenerate the server code in server/gen with the new API changes. It's best to use git to discover the added/changed files.
    3. 03

      Dependency injection

      This makes the service depend on a concrete query helper instance up front, which is not the pattern we want for new services.

      Always inject dependencies directly into service structs via the constructor.Do NOT use a session manager to stash dependencies that the service needs later.When a service needs database access, inject the DB connection and initialize query helpers (repo.New) when needed in functions.
    4. 04

      Auth context assumptions

      Avoid patterns that treat ActiveOrganizationID as optional when reading authctx. That adds defensive code around an invariant that should already hold.

      In organization-scoped handlers, assume ActiveOrganizationID is present.Session authentication can briefly produce an org-less context during login. The auth middleware handles that boundary by installing zero RBAC grants; do not spread empty-org checks into handlers.Do NOT add defensive empty checks for ActiveOrganizationID outside that boundary unless there is another concrete code path proving otherwise.
    5. 05

      Third-party clients

      This leaks vendor types into internal code and spreads nil handling into runtime call paths.

      Constructors for third-party clients should always return a usable client implementation.Avoid designs where internal code has to repeatedly check whether a client is nil before calling it.Provide a stub implementation for local development and tests, but choose between the real and stub implementation in deps.go based on c.String("environment").

    Permission review

    Static risk signals and limitations

    No configured static risk pattern was detected

    This is not proof of safety. Runtime behavior, indirect dependencies, and hidden external systems are outside the static scan.

    Evidence record

    Why each signal appears

    EvidenceSourceComputedTestedEditorial
    SignalValueEvidence typeMeaning
    Quality score96/100ComputedDocumentation, specificity, maintenance, and trust rules
    Repository stars266SourceRepository attention, not individual Skill quality
    Compatibility0 platformsSourceDeclared in the catalog source record
    Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

    Pinned source

    Provenance and original SKILL.md

    Repository
    speakeasy-api/gram
    Skill path
    .agents/skills/golang/SKILL.md
    Commit
    8af0601cf530721aaa686c2718d76e7990226d33
    License
    AGPL-3.0
    Collected
    2026-08-25
    Default branch
    main
    View the original SKILL.md

    This codebases uses features from Go 1.25 and above.

    • Be pragmatic about introducing third-party dependencies beyond what is available in go.mod and lean on the standard library when appropriate.
    • Use the Go standard library before attempting to suggest third party dependencies.
    • Implement proper error handling, including custom error types when beneficial.
    • Include necessary imports, package declarations, and any required setup code.
    • Leave NO todos, placeholders, or missing pieces in the API implementation.
    • Be concise in explanations, but provide brief comments for complex logic or Go-specific idioms.
    • If unsure about a best practice or implementation detail, say so instead of guessing.
    • Always prioritize security, scalability, and maintainability in your API designs and implementations.
    • Avoid editing any source files that have a "DO NOT EDIT" comment at start of them.
    • Store dependencies on service structs via constructor-based dependency injection. Do NOT hide dependencies in session manager state.
    • Avoid shallow helpers that are just a one-line wrapper around another method, especially when they are only used once.
    • When using a slog logger, always use the context-aware methods: DebugContext, InfoContext, WarnContext, ErrorContext.
    • When logging errors make sure to always include them in the log payload using attr.SlogError(err). Example: logger.ErrorContext(ctx, "failed to write to database", attr.SlogError(err)).
    • Any functions or methods that relate to making API calls or database queries or working with timers should take a context.Context value as their first argument.
    • IMPORTANT: never invoke go bare. Prefer a mise task when one exists; for server tests, use mise run test:server, which runs from server/ and accepts the same extra arguments as go test, e.g. mise run test:server ./internal/oops/. When no mise task exists, prefix with mise exec --, e.g. mise exec -- go test ./server/internal/oops/. A bare go can resolve to a system install (Homebrew, asdf, a distro package) whose patch version differs from the toolchain pinned in mise.toml, while GOROOT still points at the mise install. The build then fails on every stdlib package with compile: version "go1.26.4" does not match go tool version "go1.26.5". The same applies to the other pinned Go tools (golangci-lint, gotestsum, sqlc, gomigrate), and to goa, which is a go.mod tool directive and so inherits whichever toolchain invoked it.
    • Always run linters as part of finalizing your code changes. Use mise lint:server to run the linters on the server codebase.
    • The exhaustruct linter requires all struct fields to be explicitly set in struct literals. When adding new fields to a type, update ALL call sites — including places that construct the struct with zero values (e.g., MyStruct{}MyStruct{NewField: nil}).

    Comments

    • Write comments that describe current intent and behavior. Do NOT leave "intermediate" comments narrating the edit you just made (e.g. "previously this returned X, now it returns Y", "renamed from Foo"). That commentary, when appropriate, belongs in the commit message or pull request body, where it stays attached to the change instead of aging in the source. Markers that state current status are not narration and stay: Deprecated: use X instead on a symbol kept for compatibility (as its own trailing paragraph, which is the form gopls and pkg.go.dev surface to callers), build tags, //go: directives, and TODO(TICKET-123) notes. Write the rest of a deprecated symbol's doc in the present tense, describing what it still does today.
    • Do NOT write "see X" comments that point at a comment somewhere else (e.g. "see the note on Foo above", "see handler.go for details"). The target moves or gets rewritten and the pointer silently goes stale. The test is what the comment does with the name it mentions: stating the fact where the reader needs it is fine ("callers must hold Registry.mu"), sending the reader elsewhere to go find it is not ("see Registry for locking rules"). Referencing a symbol, package, ticket, or external spec that the comment is actually about is fine. Repeating a sentence or two to keep an explanation local is fine; when the full explanation is too long to restate, document it on the type or package that owns the invariant and give each use site the one-line consequence it needs.
    • Document struct fields one per field, at least on exported types. A comment placed above only the first field of a group documents just that field: go doc <Type>.<Field> and editor hovers show nothing for the rest. Grouped const and var blocks and interface methods follow the same attachment rule, and a comment above the const ( line documents the block rather than any spec in it. Put a blank line between the previous field and the next field's comment: attachment survives without it, but the blank line keeps the boundary obvious. Never leave a blank line between a comment and the field it documents, which silently detaches it. The first field in a block needs no blank line before its comment, and gofmt flags none of these mistakes.
    type Config struct {
        // Timeouts applied to outbound requests. Previously these were a single
        // Timeout field. See the note on Client above for retry interactions.
        ReadTimeout  time.Duration
        WriteTimeout time.Duration
    }
    

    Three problems in four lines: the comment narrates a past refactor, it defers to a comment that can move or disappear, and WriteTimeout ends up with no documentation at all.

    type Config struct {
        // ReadTimeout bounds how long the client waits for response headers.
        // Retries each get a fresh budget, so a request can exceed this in total.
        ReadTimeout time.Duration
    
        // WriteTimeout bounds how long the client spends sending the request body.
        WriteTimeout time.Duration
    }
    

    Updating the API

    We use Goa to design our API and generate server code. All Goa code lives in server/design. The Goa DSL is documented in https://pkg.go.dev/goa.design/goa/v3/dsl.

    To make an API change such as creating a new service or update an existing one:

    • Update the Goa design files in server/design to reflect the API change.
    • Run mise run gen:goa-server
    • This will regenerate the server code in server/gen with the new API changes. It's best to use git to discover the added/changed files.

    When implementing Goa services:

    • Ensure the service lives in a separate go package with an impl.go file such as server/internal/<service>/impl.go.
    • The general layout of the impl.go file should be as follows:
    package assets
    
    import (
    	"context"
    
    	"log/slog"
    
    	goahttp "goa.design/goa/v3/http"
    
    	gen "github.com/speakeasy-api/gram/server/gen/assets"
    	srv "github.com/speakeasy-api/gram/server/gen/http/assets/server"
    	"github.com/speakeasy-api/gram/server/internal/auth"
    )
    
    type Service struct {
    	tracer    trace.Tracer
    	logger    *slog.Logger
    	auth      *auth.Auth
      // dependencies
    }
    
    func NewService(
    	logger *slog.Logger,
    	tracerProvider trace.TracerProvider,
      auth *auth.Auth,
      // dependencies
    ) *Service {
      return &Service{
        // initialize dependencies
      }
    }
    
    var _ gen.Service = (*Service)(nil)
    var _ gen.Auther = (*Service)(nil)
    
    func Attach(mux goahttp.Muxer, service *Service) {
    	endpoints := gen.NewEndpoints(service)
    	endpoints.Use(middleware.MapErrors())
    	endpoints.Use(middleware.TraceMethods(service.tracer))
    	srv.Mount(
    		mux,
    		srv.New(endpoints, mux, goahttp.RequestDecoder, goahttp.ResponseEncoder, nil, nil),
    	)
    }
    
    func (s *Service) APIKeyAuth(ctx context.Context, key string, schema *security.APIKeyScheme) (context.Context, error) {
    	return s.auth.Authorize(ctx, key, schema)
    }
    
    func (s *Service) ListAssets(ctx context.Context, payload *gen.ListAssetsPayload) (*gen.ListAssetsResult, error) {
      // implementation
    }
    

    If you are creating a new Goa service, then make sure to attach it to the http server in server/cmd/gram/start.go.

    Dependency injection

    • Always inject dependencies directly into service structs via the constructor.
    • Do NOT use a session manager to stash dependencies that the service needs later.
    • When a service needs database access, inject the DB connection and initialize query helpers (repo.New) when needed in functions.
    • Do NOT store repo.Queries directly on a service struct for a new service.
    type Service struct {
        queries *repo.Queries
    }
    
    func NewService(db *pgxpool.Pool) *Service {
        return &Service{
            queries: repo.New(db),
        }
    }
    

    This makes the service depend on a concrete query helper instance up front, which is not the pattern we want for new services.

    type Service struct {
        db *pgxpool.Pool
    }
    
    func NewService(db *pgxpool.Pool) *Service {
        return &Service{db: db}
    }
    
    func (s *Service) Handler(ctx context.Context) error {
        queries := repo.New(s.db)
    
        if err := queries.DoThing(ctx); err != nil {
            return fmt.Errorf("do thing: %w", err)
        }
    
        return nil
    }
    

    This keeps the service dependency simple and avoids baking repo.Queries into the service shape.

    Auth context assumptions

    • In organization-scoped handlers, assume ActiveOrganizationID is present.
    • Session authentication can briefly produce an org-less context during login. The auth middleware handles that boundary by installing zero RBAC grants; do not spread empty-org checks into handlers.
    • Do NOT add defensive empty checks for ActiveOrganizationID outside that boundary unless there is another concrete code path proving otherwise.

    Avoid patterns that treat ActiveOrganizationID as optional when reading authctx. That adds defensive code around an invariant that should already hold.

    Third-party clients

    • Constructors for third-party clients should always return a usable client implementation.
    • Avoid designs where internal code has to repeatedly check whether a client is nil before calling it.
    • Provide a stub implementation for local development and tests, but choose between the real and stub implementation in deps.go based on c.String("environment").
    • Do NOT expose third-party request/response types from your wrapper to the rest of our codebase. Define our own types at the boundary.
    type Service struct {
        client *vendor.Client
    }
    
    func NewService(cfg Config) *Service {
        if cfg.APIKey == "" {
            return nil
        }
    
        return &Service{client: vendor.New(cfg.APIKey)}
    }
    
    func (s *Service) Send(ctx context.Context, req *vendor.Request) error {
        if s.client == nil {
            return nil
        }
    
        return s.client.Send(ctx, req)
    }
    

    This leaks vendor types into internal code and spreads nil handling into runtime call paths.

    type Client interface {
        Send(ctx context.Context, message Message) error
    }
    
    type Message struct {
        To      string
        Subject string
        Body    string
    }
    
    type Service struct {
        client Client
    }
    
    func NewService(client Client) *Service {
        return &Service{client: client}
    }
    

    Wire the real or stub implementation in deps.go so the service always receives a valid Client, and keep vendor-specific types inside the wrapper implementation.

    Transactional email (Loops)

    Sending transactional email goes through server/internal/email. The package wraps Loops and enforces a strongly typed Template interface.

    Adding a new template

    Follow the craft-transactional-emails skill. The Go integration is:

    1. Add a stable TemplateKey constant to server/internal/email/templates.go. Provider IDs never belong in application source.
    2. Create server/internal/email/template_<name>.go with a struct implementing Key(), Variables(), and AddToAudience().
    3. Append a fully initialized zero value to RegisteredTemplates so the application/manifest contract checks include it.
    4. Add the matching LMX and manifest.json entry under server/internal/email/loops/; merge CI creates the Loops email and gram-infra supplies its environment-specific ID at runtime.
    5. Test the key, complete snake_case variable map, and audience behavior.

    To send: call s.emailSvc.Send(ctx, recipientEmail, tmpl) where tmpl is your populated template struct.

    Variable key naming

    Variables() must return snake_case keys. Loops substitutes these keys directly into template variables — camelCase keys silently render as blank fields in the delivered email.

    Every declared key must be present in the returned map even when the value is empty. A missing key causes partial template rendering.

    func (t MyTemplate) Variables() map[string]string {
        return map[string]string{
            "approvalUrl":    t.ApprovalURL,
            "requesterEmail": t.RequesterEmail,
        }
    }
    

    camelCase keys silently render as blank fields in Loops — no error, no warning.

    func (t MyTemplate) Variables() map[string]string {
        return map[string]string{
            "approval_url":    t.ApprovalURL,
            "requester_email": t.RequesterEmail,
        }
    }
    

    AddToAudience semantics

    Controls whether Loops upserts the recipient as a contact in the audience when the email is sent.

    • Return true for user-facing emails that are part of the recipient's product journey (team invites, onboarding).
    • Return false for operational/admin emails where the recipient is incidental (admin alerts, system notifications).

    Testing patterns

    Base test setup — never pass nil for *email.Service:

    loopsClient := loops.New(ctx, logger, nil, "") // nil guardian policy is safe when key is empty; returns noop client
    noopEmailSvc := email.NewService(logger, loopsClient)
    

    Asserting on sent emails — use a capture client:

    loops.Client is our own interface (not a vendor type), so a hand-rolled capture client is appropriate here. The capture pattern lets tests assert on the exact payload sent — use it instead of testify/mock for Loops email assertions.

    type captureLoopsClient struct {
        mu   sync.Mutex
        sent []loops.SendTransactionalInput
    }
    
    func (c *captureLoopsClient) SendTransactional(_ context.Context, input loops.SendTransactionalInput) error {
        c.mu.Lock()
        defer c.mu.Unlock()
        c.sent = append(c.sent, input)
        return nil
    }
    
    func (c *captureLoopsClient) Sent() []loops.SendTransactionalInput {
        c.mu.Lock()
        defer c.mu.Unlock()
        out := make([]loops.SendTransactionalInput, len(c.sent))
        copy(out, c.sent)
        return out
    }
    

    To use it in a test, declare an instance and swap it into the service:

    captured := &captureLoopsClient{}
    svc.emailSvc = email.NewService(testenv.NewLogger(t), captured)
    

    (This assigns an unexported field — works from within the same package, which is the convention for access package tests.)

    Optional display fields — use conv.Default:

    DisplayName: conv.Default(request.DisplayName, "(unknown resource)"),
    

    Never send a template with a blank field that produces broken email copy. Apply a meaningful fallback at the Go layer, not in the Loops template.

    Function shape

    • Avoid helper functions and methods that only forward to another method with no meaningful logic.
    • Avoid extracting single-use one-liners into separate methods just for indirection.
    • Prefer inlining trivial behavior at the call site unless the extracted function adds reuse, naming value, or non-trivial logic.
    func (s *Service) listWidgets(ctx context.Context) error {
        return s.repo.ListWidgets(ctx)
    }
    
    func (s *Service) List(ctx context.Context) error {
        return s.listWidgets(ctx)
    }
    

    The wrapper adds no abstraction and is only used once.

    func (s *Service) List(ctx context.Context) error {
        return s.repo.ListWidgets(ctx)
    }
    

    Error handling

    In low-level functions, use fmt.Errorf to wrap errors with distinct and useful context:

    func SaveUser(repo Repository, u User) error {
      err := repo.Save(u)
      if err != nil {
        return fmt.Errorf("failed to save user: %w", err)
      }
      return nil
    }
    

    Do not need to use "failed to" language.

    func SaveUser(repo Repository, u User) error {
      err := repo.Save(u)
      if err != nil {
        return fmt.Errorf("run database query: %w", err)
      }
      return nil
    }
    

    Do not use generic language that doesn't add any context and doesn't improving searching for errors in the codebase.

    func SaveUser(repo Repository, u User) error {
      err := repo.Save(u)
      if err != nil {
        return fmt.Errorf("save user: %w", err)
      }
      return nil
    }
    

    This is much better. The error message is concise and to the point and unique to the call site.

    In higher-level functions of the server/ codebase, which include HTTP service handlers, use the server/internal/oops package which allows us to wrap internal errors with user-facing error messages.

    func (s *Service) ListDeployments(ctx context.Context, form *gen.ListDeploymentsPayload) (res *gen.ListDeploymentResult, err error) {
      var cursor uuid.NullUUID
    	if form.Cursor != nil {
    		c, err := uuid.Parse(*form.Cursor)
    		if err != nil {
    			return nil, oops.E(oops.CodeBadRequest, err, "invalid cursor").LogError(ctx, s.logger)
    		}
    
    		cursor = uuid.NullUUID{UUID: c, Valid: true}
    	}
    }
    

    Logging

    • Use log/slog for logging.
    • ALWAYS use logging attributes defined in server/internal/attr/conventions.go when logging in the server codebase.
    • Where appropriate, create child loggers using logger.With(attr.SlogXXX(...)) to capture contextual attributes for logging in later parts of code.
    • DO NOT spam the codebase with log statements. Focus on logging errors where appropriate and reduce the noise from excessive info-level logs.
    logger.InfoContext(ctx, "user created", "user_id", userID)
    

    This is bad because it doesn't use the attributes from the convention package.

    import "github.com/speakeasy-api/gram/functions/internal/attr"
    
    func Example() {
      logger.Error("failed to create user", attr.SlogError(err))
    }
    

    This is bad because it uses logger.Error instead of logger.ErrorContext.

    import "github.com/speakeasy-api/gram/functions/internal/attr"
    
    func Example(ctx context.Context) {
      logger.ErrorContext(ctx, "failed to create user", attr.SlogError(err))
    }
    

    This is great because:

    • It uses logger.ErrorContext which is the convention for logging in the server codebase.
    • It uses the attr.SlogError attribute from the attr package.

    Conversion utilities (server/internal/conv)

    Use the conv package for common type conversions instead of writing inline helpers. Key functions:

    • conv.PtrEmpty(v) — If v is not the zero value, return a pointer to v; otherwise, return nil.
    • conv.PtrValOr(ptr, default) — dereference a pointer with a fallback default.
    • conv.Default(val, default) — return val unless it is the zero value, then return default.
    • conv.ToPGText, conv.ToPGTextEmpty, conv.PtrToPGText, conv.PtrToPGTextEmpty — convert strings to pgtype.Text.
    • conv.FromPGText, conv.FromPGBool — convert pgtype values to Go pointer types.
    • conv.PtrToPGBool — convert a *bool to pgtype.Bool.
    • conv.Ternary(cond, trueVal, falseVal) — inline conditional expression.

    Do NOT reimplement pointer helpers, ternary expressions, or pgtype conversions inline. Always reach for conv first.

    Observability (server/internal/o11y)

    Use the o11y package for deferred cleanup and error logging. Two key functions:

    o11y.LogDefer

    func LogDefer(ctx context.Context, logger *slog.Logger, cb func() error) error
    

    Use LogDefer when a cleanup operation's error should be logged. Wrap cleanup calls with defer o11y.LogDefer(...) so failures are always visible in logs.

    defer o11y.LogDefer(ctx, logger, func() error { return file.Close() })
    

    o11y.NoLogDefer

    func NoLogDefer(cb func() error)
    

    Use NoLogDefer when a cleanup operation's error can be silently discarded — for example, rolling back a database transaction (which is a no-op if the transaction already committed) or closing an HTTP response body.

    dbtx, err := s.repo.DB().Begin(ctx)
    if err != nil {
        return nil, oops.E(oops.CodeUnexpected, err, "error accessing resource").LogError(ctx, logger)
    }
    defer o11y.NoLogDefer(func() error { return dbtx.Rollback(ctx) })
    
    defer o11y.NoLogDefer(func() error { return resp.Body.Close() })
    
    • ALWAYS use o11y.LogDefer or o11y.NoLogDefer for deferred cleanup instead of bare defer resource.Close() calls. Bare defers silently discard errors with no traceability.
    • Choose LogDefer when the error matters for debugging (file I/O, critical resource cleanup).
    • Choose NoLogDefer when the error is expected or inconsequential (transaction rollbacks, response body closes).

    Testing

    • When writing assertions, use github.com/stretchr/testify/require exclusively.
    • Avoid using time.Sleep to wait for eventual consistency or async state in tests. It is reported by the forbidigo rule GG013 (enforced repo-wide, with a small grandfathered allowlist in server/.golangci.yaml). Poll instead: require.EventuallyWithT to wait until assertions pass or require.Never to assert a condition never becomes true. Inside an EventuallyWithT closure, make assertions with assert.* against the supplied *assert.CollectT — the one sanctioned use of assert over require.
    • Prefer testing/synctest (synctest.Test + synctest.Wait) for testing purely in-process timer/debounce logic. This is one of the few allowed time.Sleep use cases in tests since it is required for advancing the fake clock inside a synctest bubble.
    • In tests, use t.Context() instead of context.Background(), except inside t.Cleanup(func()) callbacks.
    • IMPORTANT: avoid using t.Run to create subtests. Prefer writing separate test functions instead.
    • All test setup which includes spinning up databases, caches and background workers must go in setup_test.go files. Look for these across the codebase for inspiration and guidance.
    • NEVER write raw SQL in tests for any Postgres operation — SELECT, INSERT, UPDATE, DELETE, transactions (Begin/BeginTx), CopyFrom, and SendBatch are all covered. Use SQLc-generated methods. Default to adding new fixture queries in the relevant domain package's own queries.sql (e.g. a toolsets-shaped fixture goes in server/internal/toolsets/queries.sql, not in testenv). Reach for server/internal/testenv/queries.sql (and testenv/testrepo) only when a fixture query is genuinely reused across multiple packages. The glint no-testing-raw-sql rule enforces this against *pgxpool.Pool, *pgx.Conn, pgx.Tx, and pgx.Querier receivers in *_test.go. ClickHouse uses a different driver and is not flagged.
    • Use github.com/stretchr/testify/mock for mocking third-party libraries in tests instead of ad hoc fakes around vendor types.
    • Use testenv.NewLogger(t), testenv.NewTracerProvider(t), and testenv.NewMeterProvider(t) instead of constructing loggers or noop OTel providers inline. testenv.NewLogger(t) discards in normal runs and emits pretty logs under go test -v, which inline slog.New(slog.DiscardHandler) and slog.New(slog.NewTextHandler(os.Stdout, nil)) do not. Exception: tests that assert on log output should use a capturing handler over a bytes.Buffer.
    ctx := context.Background()
    

    This loses the test lifecycle context that Go now provides directly on *testing.T.

    ctx := t.Context()
    
    type mockEmailClient struct {
        mock.Mock
    }
    
    func (m *mockEmailClient) Send(ctx context.Context, message Message) error {
        args := m.Called(ctx, message)
        return args.Error(0)
    }
    

    Use testify/mock when mocking integrations so expectations stay explicit and consistent across tests.

    Frequently asked questions

    What to verify before installation and use

    What does the golang source document cover?

    Three problems in four lines: the comment narrates a past refactor, it defers to a comment that can move or disappear, and WriteTimeout ends up with no documentation at all.

    How do I install golang?

    The source record exposes this install command: npx skills add https://github.com/speakeasy-api/gram --skill ".agents/skills/golang". Inspect the command and pinned source before running it.

    Alternatives

    Compare before choosing

    Computed 10045,511

    coreyhaines31/marketingskills

    ab-testing

    When the user wants to plan, design, or implement an A/B test or experiment, or build a growth experimentation program. Also use when the user mentions "A/B test," "split test," "experiment," "test this change," "variant copy," "multivariate test," "hypothesis," "should I test this," "which version is better," "test two versions," "statistical significance," "how long should I run this test," "growth experiments," "experiment velocity," "experiment backlog," "ICE score," "experimentation program

    Computed 10029,034

    garrytan/gbrain

    bulk-ingestion

    End-to-end discipline for turning any large data source (audio libraries, email takeouts, document corpora, chat exports, API dumps) into brain pages at scale. The lifecycle spine: SCHEMA → ACCESS → TRIAL → EVALUATE → IMPROVE → CODIFY → TEST → SKILLIFY → BULK → MONITOR. State is tracked in a durable JSON manifest (see MANIFEST-PATTERN.md) so any crash, session boundary, or subagent fan-out resumes from ground truth instead of memory.

    Computed 10024,921

    alirezarezvani/claude-skills

    app-store-optimization

    App Store Optimization (ASO) toolkit for researching keywords, analyzing competitor rankings, generating metadata suggestions, and improving app visibility on Apple App Store and Google Play Store. Use when the user asks about ASO, app store rankings, app metadata, app titles and descriptions, app store listings, app visibility, or mobile app marketing on iOS or Android. Supports keyword research and scoring, competitor keyword analysis, metadata optimization, A/B test planning, launch checklist

    Computed 1005,241

    dotnet/skills

    migrate-vstest-to-mtp

    Migrates .NET test projects from VSTest to Microsoft.Testing.Platform (MTP). Use when user asks to "migrate to MTP", "switch from VSTest", "enable Microsoft.Testing.Platform", "use MTP runner", set OutputType=Exe only for test projects in Directory.Build.props, or mentions EnableMSTestRunner, EnableNUnitRunner, or UseMicrosoftTestingPlatformRunner. USE FOR: MTP behavioral differences vs VSTest (exit code 8, zero tests discovered, --ignore-exit-code, TESTINGPLATFORM_EXITCODE_IGNORE); centralizing