Go backend
Multi-account CLI companion for Claude Code that tracks usage limits, launches configured sessions, and applies skills & output styles.
npx -y skills add Tanq16/claudex --skill go-backendAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 3 stars3 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Use when implementing Go backend logic - covers internal package architecture, error handling, HTTP servers, storage patterns, and OAuth authentication for CLI clients (browser/device/manual flows, not server-side web OAuth)
SKILL.md
11.1 KB, as published. Nobody here has run it
Go Backend
Architecture and implementation patterns for Go internal packages.
When to Use
Use this skill when:
- Structuring
internal/packages - Implementing business logic
- Setting up HTTP servers
- Designing storage/persistence layer
- Handling errors across packages
- Adding OAuth authentication to CLI tools
Requires: go-foundations for project layout and principles.
Web Only constraint: Internal packages in Web Only projects — and the server layer of CLI + Web hybrids — must NOT import utils/. Use log.Printf with manual level prefixes (e.g., log.Printf("ERROR ...")) and log.Fatal()/log.Fatalf() for fatal errors. Keep messages generic — no package-name prefix. (A hybrid's CLI-operation packages follow CLI Only conventions instead.)
Start here — required reading
Read the Always file now, in full, before building the server — it carries the canonical server structure you'll be held to. Read the When file before the sub-task it names; a subagent may read it if you delegate that work.
Always:
./references/http-server-template.md— the canonical embedded-staticnet/httpserver (fullserver.go, skeleton, middleware)
When adding OAuth authentication to a CLI client:
./references/auth-patterns.md— completeinternal/auth/auth.go+cmd/login.gotemplates
Package Architecture
By Domain/Feature (Default)
internal/
├── auth/ # Authentication logic
├── download/ # Download functionality
└── server/ # HTTP server + frontend
By Layer (When Many Features)
When project has many features across multiple layers:
internal/
├── handlers/ # HTTP handlers by feature
│ ├── auth.go
│ └── download.go
├── services/ # Business logic by feature
│ ├── auth.go
│ └── download.go
├── models/ # Data structures
└── server/ # Server setup
Decision rule: Start with domain/feature. Switch to layered when you have 5+ features that each need handlers, services, and models.
Error Handling
Two Package Types
Task Packages (internal logic, potentially portable to pkg/):
- Return errors as-is
- Small, focused methods
- No wrapping, no logging
// internal/download/client.go
func (c *Client) FetchFile(url string) ([]byte, error) {
resp, err := c.httpClient.Get(url)
if err != nil {
return nil, err // Return as-is
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("unexpected status: %d", resp.StatusCode)
}
return io.ReadAll(resp.Body)
}
Interaction Packages (Cobra commands, HTTP handlers):
- Wrap errors with context
- Handle logging
- User-facing error messages
CLI Only pattern (uses utils):
// cmd/download.go
Run: func(cmd *cobra.Command, args []string) {
client := download.NewClient()
data, err := client.FetchFile(url)
if err != nil {
u.PrintFatal(fmt.Sprintf("Failed to download from %s", url), err)
}
u.PrintSuccess("Download complete")
}
Web Only pattern (the interaction layer is HTTP handlers, shown in the HTTP Server Pattern section, which use log.Printf). For Cobra commands in a Web Only project (or a hybrid's serve command):
// cmd/download.go
Run: func(cmd *cobra.Command, args []string) {
client := download.NewClient()
data, err := client.FetchFile(url)
if err != nil {
log.Fatalf("ERROR Failed to download from %s: %v", url, err)
}
log.Printf("INFO Download complete")
}
Rationale
Task packages stay portable—if moved to pkg/ later, no changes needed. Context and logging happen at boundaries (commands, handlers).
HTTP Server Pattern
Use standard net/http (KISS principle) — no third-party routers (gin, chi, echo). A Server struct holds host, port, and an *http.ServeMux; Setup() mounts embedded static files and routes; Run() calls http.ListenAndServe.
//go:embed static
var staticFiles embed.FS
func (s *Server) Setup() error {
staticFS, err := fs.Sub(staticFiles, "static")
if err != nil {
return err
}
s.mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.FS(staticFS))))
s.mux.HandleFunc("/api/health", s.handleHealth)
s.mux.HandleFunc("/", s.handleIndex) // serves static/index.html
return nil
}
go-backend owns the canonical embedded-static server — the full server.go (struct, New, Run, handleIndex, health handler), the skeleton variant, and the middleware wrapper pattern all live in ./references/http-server-template.md. go-frontend references that file rather than redefining the boilerplate.
Storage Pattern
Most projects: JSON/file-based, stateless.
When persistence needed, use interface abstraction:
// internal/storage/storage.go
package storage
type Store interface {
Get(key string) ([]byte, error)
Set(key string, value []byte) error
Delete(key string) error
List() ([]string, error)
}
// internal/storage/json.go
type JSONStore struct {
path string
}
func NewJSONStore(path string) *JSONStore {
return &JSONStore{path: path}
}
func (s *JSONStore) Get(key string) ([]byte, error) {
// Read from JSON file
}
// internal/storage/postgres.go
type PostgresStore struct {
db *sql.DB
}
func NewPostgresStore(connStr string) (*PostgresStore, error) {
// Connect to Postgres
}
func (s *PostgresStore) Get(key string) ([]byte, error) {
// Query Postgres
}
Usage
// In command or server setup
var store storage.Store
if usePostgres {
store, err = storage.NewPostgresStore(connStr)
} else {
store = storage.NewJSONStore(dataPath)
}
// Pass store to handlers/services
svc := myservice.New(store)
Authentication Pattern (CLI Only)
For CLI tools that authenticate with OAuth2 providers (Google, GitHub, Microsoft, etc.), use the three-mode login pattern in internal/auth/.
Three Login Modes
| Mode | Flag | How It Works | Environment |
|---|---|---|---|
| Callback (default) | (none) | Opens browser, localhost server receives redirect | Interactive desktop |
| Device | --device-login | Shows URL + code, polls until authorized | Headless / SSH / server |
| Manual | --manual | Shows URL, user pastes authorization code | Last resort / no device flow support |
The user explicitly selects their mode via flags — no auto-fallback chain. Default opens browser; if it fails on headless, the error message directs them to --device-login.
Key Design Decisions
Login(config, mode)takes a mode string — the command layer maps flags to mode, auth package handles the flowopenBrowserreturns error — fast-fail on headless instead of hanging for 5 minutes- Device flow uses
oauth2.Config.DeviceAuth()andDeviceAccessToken()— built intogolang.org/x/oauth2, handles polling and backoff automatically - Manual flow accepts both bare codes and full URLs via
extractCode()helper - Token persistence:
~/.config/[APP_NAME]/token.jsonwith0600permissions - Auto-refresh on load:
GetHTTPClient()loads cached token, refreshes if expired, saves if refreshed
Provider Support
Not all providers support device authorization (RFC 8628). When unsupported, omit loginWithDevice and the --device-login flag, keeping only callback and manual modes.
| Provider | Device Auth | Device Auth URL |
|---|---|---|
| Yes | https://oauth2.googleapis.com/device/code | |
| Microsoft | Yes | https://login.microsoftonline.com/common/oauth2/v2.0/devicecode |
| GitHub | Yes | https://github.com/login/device/code |
| Box.com | No | — |
Output Tier Usage
Login flows use u.PrintInfo for instructions/status and u.PrintGeneric for data (URLs, codes). u.PromptInput in manual mode reads from pipe in --for-ai mode. u.PrintFatal and u.PrintSuccess are used at the command layer only.
Implementation
Use ./references/auth-patterns.md for the complete internal/auth/auth.go and cmd/login.go templates.
Config Struct Pattern
Define config structs that map to Cobra flags:
// internal/download/config.go
package download
type Config struct {
URL string
OutputPath string
Concurrency int
Timeout time.Duration
}
// internal/download/downloader.go
func Download(cfg Config) error {
// Use cfg fields
}
CLI Only (uses u.PrintFatal):
// cmd/download.go
Run: func(cmd *cobra.Command, args []string) {
cfg := download.Config{
URL: downloadFlags.url,
OutputPath: downloadFlags.output,
Concurrency: downloadFlags.concurrency,
Timeout: time.Duration(downloadFlags.timeout) * time.Second,
}
if err := download.Download(cfg); err != nil {
u.PrintFatal("Download failed", err)
}
}
Web Only (uses log.Fatalf):
// cmd/download.go
Run: func(cmd *cobra.Command, args []string) {
cfg := download.Config{
URL: downloadFlags.url,
OutputPath: downloadFlags.output,
Concurrency: downloadFlags.concurrency,
Timeout: time.Duration(downloadFlags.timeout) * time.Second,
}
if err := download.Download(cfg); err != nil {
log.Fatalf("ERROR Download failed: %v", err)
}
}
Common Patterns
HTTP Client with Defaults
// internal/httpclient/client.go
package httpclient
import (
"net/http"
"time"
)
func New() *http.Client {
return &http.Client{
Timeout: 30 * time.Second,
Transport: &http.Transport{
MaxIdleConns: 100,
MaxIdleConnsPerHost: 10,
IdleConnTimeout: 90 * time.Second,
},
}
}
Parallelization (Vanilla Goroutines)
Don't abstract—keep explicit:
func ProcessItems(items []string, concurrency int) error {
sem := make(chan struct{}, concurrency)
errCh := make(chan error, len(items))
var wg sync.WaitGroup
for _, item := range items {
sem <- struct{}{} // Acquire (blocks if `concurrency` already running)
wg.Go(func() {
defer func() { <-sem }() // Release
if err := processItem(item); err != nil {
errCh <- err
}
})
}
wg.Wait()
close(errCh)
// Collect errors
var errs []error
for err := range errCh {
errs = append(errs, err)
}
if len(errs) > 0 {
return fmt.Errorf("%d items failed", len(errs))
}
return nil
}
References
| File | Purpose |
|---|---|
./references/http-server-template.md | Canonical embedded-static net/http server (full server.go, skeleton variant, middleware) — referenced by go-frontend |
./references/auth-patterns.md | Complete OAuth auth templates (internal/auth/auth.go and cmd/login.go) |