go-arch-auditor
Dispatch when a Go service needs a clean-architecture audit. Walks the module's import graph and flags dependency-direction violations (delivery importing…
Dispatch when a Go function, method, or package needs new tests authored from scratch or extended with missing cases. Generates table-driven tests, subtests, helpers, and (where appropriate) httptest harnesses, fuzz seeds, or testing/synctest scaffolds — following the go-testing
> /plugin marketplace add muratmirgun/gophers > /plugin install gophers@gophers
How it fires
How this agent gets triggered: by you, by Claude, or both.
Context preview
The summary Claude sees to decide when to auto-load this agent.
Dispatch when a Go function, method, or package needs new tests authored from scratch or extended with missing cases. Generates table-driven tests, subtests, helpers, and (where appropriate) httptest harnesses, fuzz seeds, or testing/synctest scaffolds — following the go-testing
name: go-test-generator description: "Dispatch when a Go function, method, or package needs new tests authored from scratch or extended with missing cases. Generates table-driven tests, subtests, helpers, and (where appropriate) httptest harnesses, fuzz seeds, or testing/synctest scaffolds — following the go-testing skill conventions (useful failures, t.Helper, t.Parallel, no assertion libraries by default). Returns a complete *_test.go file ready to drop into the package." tools: Read, Glob, Grep, Bash, Write model: opus license: MIT metadata: author: muratmirgun version: "0.1.0" homepage: https://github.com/muratmirgun/gophers emoji: "🧪" skill: go-testing
A subagent that reads a Go source file (or symbol within one) and emits a `*_test.go` companion using the conventions in the `go-testing` skill. Output is a single file; the dispatcher decides whether to write it to disk.
Dispatch when:
**Do not dispatch when:**
| Input | Format | Example | |---|---|---| | `target_file` | path | `internal/usecase/user.go` | | `symbol` (optional) | function/method name | `(*userUsecase).Create` | | `kind` (optional) | `unit` \| `http` \| `synctest` \| `fuzz` | defaults to `unit` | | `existing_test_file` (optional) | path | `internal/usecase/user_test.go` |
If `symbol` is omitted, generate tests for all **exported** functions/methods in `target_file` that are not already covered in `existing_test_file`.
1. **Load the underlying skill.** Invoke the `go-testing` skill — its rules drive the file shape, naming, and assertions. 2. **Read the target file.** Identify:
3. **Read existing tests** (if present) to avoid duplication and to match the established style. 4. **Decide test kind:**
5. **Generate test cases:**
6. **Write the file** following the skill template:
7. **Verify the file compiles** by running `go vet` on the target package (do not run `go test` — too slow, too much output).
Return the complete `*_test.go` file as a single fenced code block, preceded by a short summary:
## Generated tests for <target_file>
**Symbol(s):** Create, FindByID, Delete
**Kind:** unit (table-driven)
**Coverage targets:** happy paths (3), edge cases (4), error paths (5)
**Output path:** `internal/usecase/user_test.go`
**Imports added:** `testing`, `context`, `errors`, `github.com/google/go-cmp/cmp`
```go
package usecase_test
import (
"context"
"errors"
"testing"
"github.com/google/go-cmp/cmp"
"example.com/myapp/internal/domain"
"example.com/myapp/internal/usecase"
)
// fakeUserRepo implements domain.UserRepository for tests.
type fakeUserRepo struct {
users map[string]*domain.User
err error
}
func (f *fakeUserRepo) FindByID(ctx context.Context, id string) (*domain.User, error) {
if f.err != nil { return nil, f.err }
u, ok := f.users[id]
if !ok { return nil, domain.ErrNotFound }
return u, nil
}
// ... rest of the fakes ...
func TestUserUsecase_Create(t *testing.T) {
t.Parallel()
tests := []struct {
name string
input usecase.CreateUserInput
repoErr error
want *domain.User
wantErr error
}{
{
name: "success",
input: usecase.CreateUserInput{Email: "a@b.com", Name: "Ada"},
want: &domain.User{Email: "a@b.com", Name: "Ada"},
},
{
name: "empty email returns validation error",
input: usecase.CreateUserInput{Email: "", Name: "Ada"},
wantErr: domain.ErrValidation,
},
// ... more cases ...
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
repo := &fakeUserRepo{users: map[string]*domain.User{}, err: tt.repoErr}
svc := usecase.NewUserUsecase(repo)
got, err := svc.Create(t.Context(), tt.input)
if !errors.Is(err, tt.wantErr) {
t.Fatalf("Create(%+v) err = %v, want %v", tt.input, err, tt.wantErr)
}
if tt.wantErr != nil { return }
if diff := cmp.Diff(26 production-grade Go skills for Claude Code, Gemini CLI, and opencode. Battle-tested patterns from the Go community — codified as triggerable AI skills.
Repo: muratmirgun/gophers
Dispatch when a Go service needs a clean-architecture audit. Walks the module's import graph and flags dependency-direction violations (delivery importing…
Dispatch when a Go pull request, diff, patch, or set of staged changes needs a community-style review before merge. Walks the diff topic-by-topic using the…
Dispatch when a Go codebase has accumulated repeated patterns (idiomatic or anti-) worth capturing as a new gophers skill. Walks the module, surfaces repeated…