# Chainsafe Go Architect

> Architectural guidance for designing Go services and systems at ChainSafe (Gossamer and Go projects). Use whenever the user starts a new Go service, designs a Go module, writes an ADR for Go work, picks concurrency patterns, decides on a public API surface, structures a Go workspace, or makes any Go-specific architectural decision. EVEN IF the user does not explicitly say "architecture" — triggers on "design a Go service", "new Go module", "Go project layout", "concurrency model in Go", "public API for this Go package", "ADR for Go", "internal vs pkg", "channels or mutexes", "interface design in Go", "context propagation", "goroutine ownership". Defers to `.invariants` for invariants. Do NOT use for line-level Go coding (use chainsafe-go-developer) or Go PR review (use chainsafe-go-reviewer).

- Skill: `chainsafe/chainsafe-go-architect` (Agent Skill)
- Install (CLI): `npx skillmds@latest add chainsafe/chainsafe-go-architect`
- Raw SKILL.md: https://api.skillmd.com/api/skills/chainsafe/chainsafe-go-architect/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: chainsafe (https://skillmd.com/u/chainsafe)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/chainsafe/chainsafe-go-architect

---


# Go Architect

Use this when designing Go systems at ChainSafe — Gossamer-shaped work or any Go service/library.

## Operating context

You are the architect role for Go work. The architectural framework (invariant naming, lifecycle, testability) is `.invariants`; consult [`invariants/invariants-framework.md`](../../invariants/invariants-framework.md) and [boorich/.invariants-starter-kit](https://github.com/boorich/.invariants-starter-kit) before proposing a design. This skill covers what is Go-specific *under* that framework.

The full reference is [`languages/go/architect.md`](../../languages/go/architect.md). Load that file for the complete guidance.

## Key Go-specific decisions

When designing a Go system or module, address:

- **Project layout.** `cmd/<app>/main.go` for binaries (minimal logic, just wiring). `internal/` is the default home for all non-library code. `pkg/` is *limited and stable* — a package moves there only when it has proven stable with deep test coverage and the team commits to semver.
- **Public surface discipline.** Start everything in `internal/`. Export only when keeping it private costs more than locking in a public API.
- **Concurrency model.**
  - Lifetimes via `context.Context`. Every long-running operation accepts `ctx` as the first parameter.
  - Channels for ownership transfer; mutexes for shared state. Mixing patterns in one component is a smell.
  - Bounded concurrency — never unbounded `go func()` spawn. Use worker pools, semaphores, or `errgroup` with limits.
  - No package-level mutable state.
- **Error model.** Errors are values. Sentinel errors with `errors.Is`, typed errors with `errors.As`. `fmt.Errorf("...: %w", err)` to preserve context. Never `panic` for non-fatal errors.
- **Dependency injection.** Functional options or explicit `Settings` structs. No globals, no hidden singletons.
- **Defensive network & disk I/O.** Every external network call, database query, or stream reader must have an explicit timeout — `context.WithTimeout` on the call, or socket/read deadlines where context isn't threaded through. A `ctx` without a deadline is not a timeout; an unbounded read is a hang waiting to happen.
- **API & storage isolation.** Keep internal domain models separate from external transport layers. Define Data Transfer Objects (DTOs) for external APIs and database schemas, and map them explicitly to internal models at the boundary. This is for *external* edges — don't introduce DTOs between internal packages.

## ADR template for Go work

Every non-trivial Go ADR should cover:

- Public surface: what's exported, why.
- Concurrency commitments: goroutine ownership, context propagation, cancellation.
- Error contract: which errors callers see, sentinel vs typed vs wrapped.
- Resource ownership: connections, files, goroutines — who closes them, when.
- Invariants impacted: deep links into `.invariants`.

## Defer to `.invariants` for

- The invariant definitions and lifecycle.
- Cross-service contracts.
- Failure-mode invariants.

This skill covers Go-specific *shape*; the framework is upstream.

## Anti-patterns to flag at design time

- Wide `pkg/` directory.
- Goroutines without `context.Context`.
- `interface{}` / `any` crossing module boundaries.
- `init()` functions doing work.
- Reach for `sync.Map` when a domain-specific structure would do.

## Related

- Full reference: [`languages/go/architect.md`](../../languages/go/architect.md)
- Sister roles: `chainsafe-go-developer` (implementation), `chainsafe-go-reviewer` (PR review)
- Workflow: `chainsafe-research-plan-implement` for the design-to-implementation flow
- Framework: [`invariants/invariants-framework.md`](../../invariants/invariants-framework.md)

