Swiftui View Refactor
Dimillian/Skills
Refactor and review SwiftUI view files with strong defaults for small dedicated subviews, MV-over-MVVM data flow, stable view trees, explicit dependency injection, and correct Observation usage.
Go 1.24–1.27 coding guidelines for the dimetron/pi-go AI agent runtime.
$ npx skills add dimetron/pi-go --skill code-guidelines-go -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install dimetron/pi-go code-guidelines-go --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/dimetron/pi-go.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.pi-go/skills/code-guidelines-go .claude/skills/code-guidelines-go && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "code-guidelines-go" agent skill from https://github.com/dimetron/pi-go/tree/main/.pi-go/skills/code-guidelines-go into .claude/skills/code-guidelines-go/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "code-guidelines-go", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/dimetron/pi-go/tree/main/.pi-go/skills/code-guidelines-goType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add dimetron/pi-go --skill code-guidelines-go -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install dimetron/pi-go code-guidelines-go --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/dimetron/pi-go.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.pi-go/skills/code-guidelines-go .agents/skills/code-guidelines-go && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "code-guidelines-go" agent skill from https://github.com/dimetron/pi-go/tree/main/.pi-go/skills/code-guidelines-go into .agents/skills/code-guidelines-go/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "code-guidelines-go", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add dimetron/pi-go --skill code-guidelines-go -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install dimetron/pi-go code-guidelines-go --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/dimetron/pi-go.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.pi-go/skills/code-guidelines-go .cursor/skills/code-guidelines-go && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "code-guidelines-go" agent skill from https://github.com/dimetron/pi-go/tree/main/.pi-go/skills/code-guidelines-go into .cursor/skills/code-guidelines-go/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "code-guidelines-go", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/dimetron/pi-go.git --path .pi-go/skills/code-guidelines-go--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add dimetron/pi-go --skill code-guidelines-go -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install dimetron/pi-go code-guidelines-go --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/dimetron/pi-go.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.pi-go/skills/code-guidelines-go .gemini/skills/code-guidelines-go && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "code-guidelines-go" agent skill from https://github.com/dimetron/pi-go/tree/main/.pi-go/skills/code-guidelines-go into .gemini/skills/code-guidelines-go/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "code-guidelines-go", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install dimetron/pi-go code-guidelines-goInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add dimetron/pi-go --skill code-guidelines-go -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/dimetron/pi-go.git skills-src && mkdir -p .github/skills && cp -r skills-src/.pi-go/skills/code-guidelines-go .github/skills/code-guidelines-go && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "code-guidelines-go" agent skill from https://github.com/dimetron/pi-go/tree/main/.pi-go/skills/code-guidelines-go into .github/skills/code-guidelines-go/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "code-guidelines-go", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add dimetron/pi-go --skill code-guidelines-go -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install dimetron/pi-go code-guidelines-go --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/dimetron/pi-go.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.pi-go/skills/code-guidelines-go .opencode/skills/code-guidelines-go && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "code-guidelines-go" agent skill from https://github.com/dimetron/pi-go/tree/main/.pi-go/skills/code-guidelines-go into .opencode/skills/code-guidelines-go/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "code-guidelines-go", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
code-guidelines-goGo 1.24–1.27 coding guidelines for the dimetron/pi-go AI agent runtime.
Code Guidelines Go is an agent skill from dimetron/pi-go. Go 1.24–1.27 coding guidelines for the dimetron/pi-go AI agent runtime. Use this skill whenever writing, reviewing, or refactoring ANY Go code in pi-go. This covers idiomatic style, error handling, concurrency, project layout, testing (table-driven, fuzz, benchmarks, synctest), new stdlib usage, golangci-lint v2 configuration, slog logging, and manual dependency injection with functional options. Always consult this skill before generating Go code for pi-go, even for small snippets, to ensure every output is…
Its SKILL.md is about 5.8k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Development, covering Design patterns and Refactoring. The repository describes itself as: Go implementation of AI coding agent. The licence is MIT.
10 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 24d1f2b. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
goFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Code Guidelines Go loads about 5.8k tokens when it runs. Until then it costs about 139 tokens; SKILL.md has 1,098 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from dimetron/pi-go at commit 24d1f2b, republished under its MIT licence (© dimetron). 1,098 words, ~5,758 tokens.
.claude/skills/code-guidelines-go/SKILL.md (or your agent's skills folder).Project: github.com/dimetron/pi-go — Go-native AI coding agent runtime
Layout: cmd/pi/ · internal/ · .pi-go/ · .vibe/compiled/ · scripts/
Min version: Go 1.24 (tool directive support) | Target: Go 1.27
For what Go 1.27 changed — generic methods, struct-literal field selectors,
encoding/json/v2, the stdlibuuidpackage, removals that break a build, and theGOEXPERIMENT=nonetrap on this machine — see thego-127skill.
config ✓ agentUtils ✗agent → type Runner (not AgentRunner)util, common, types, helpersself/thisID, URL, HTTP, LLM — enforced by staticchecki, ctx, err), descriptive in large scopes// ✓ Correct
func (r *Runner) Execute(ctx context.Context) error { ... }
func (r *Runner) Stop() { ... }
// ✗ Wrong
func (self *Runner) Execute(ctx context.Context) error { ... }
func (runner *Runner) Stop() { ... }-er suffix (Reader, Handler, Closer)// consumer defines what it needs (internal/agent/)
type LLMClient interface {
Complete(ctx context.Context, prompt string) (string, error)
}
// producer returns concrete struct (internal/llm/)
func NewOpenAIClient(apiKey string) *OpenAIClient { ... }Every exported name starts its comment with the name itself:
// Package agent provides the core AI agent runtime for pi-go.
package agent
// Runner orchestrates tool calls and LLM interactions.
type Runner struct { ... }
// Execute runs the agent loop until completion or context cancellation.
func (r *Runner) Execute(ctx context.Context, task string) error { ... }Avoid deep nesting. Return errors early, keep the happy path at the left edge:
// ✓ Guard clauses
func (r *Runner) Start(ctx context.Context) error {
if r.running {
return ErrAlreadyRunning
}
if r.client == nil {
return errors.New("nil client")
}
return r.loop(ctx)
}
// ✗ Nested conditionals
func (r *Runner) Start(ctx context.Context) error {
if !r.running {
if r.client != nil {
return r.loop(ctx)
}
return errors.New("nil client")
}
return ErrAlreadyRunning
}Extract testable logic into pure functions that take inputs and return outputs. Keep side effects (network, disk, logging) at the edges:
// ✓ Pure — easy to test, no mocks needed
func buildPrompt(system string, history []Message, tools []Tool) string { ... }
func mergeToolResults(existing, incoming []ToolResult) []ToolResult { ... }
func selectModel(budget Budget, task Task) string { ... }
// Wire I/O at the caller
func (r *Runner) Execute(ctx context.Context, task string) error {
prompt := buildPrompt(r.system, r.history, r.tools) // pure
resp, err := r.client.Complete(ctx, prompt) // side effect
...
}init() hides execution order and makes testing harder. Wire everything in main or constructors:
// ✗ Hidden global state
func init() { registry.Register("search", searchTool) }
// ✓ Explicit wiring
func NewRegistry(tools ...Tool) *Registry { ... }Prefer returning new values over mutating inputs. Makes data flow visible:
// ✓ Value in, value out
func withDefaults(cfg Config) Config {
if cfg.Timeout == 0 { cfg.Timeout = 30 * time.Second }
if cfg.Model == "" { cfg.Model = "claude-sonnet-4-5-20250514" }
return cfg
}
// ✗ Mutate in place — caller can't see what changed
func applyDefaults(cfg *Config) { ... }Use named function types to simplify callback and middleware patterns:
// Named function type — implements Handler implicitly
type ToolFunc func(ctx context.Context, input json.RawMessage) (string, error)
// Higher-order function — returns a decorated version
func WithTimeout(d time.Duration, fn ToolFunc) ToolFunc {
return func(ctx context.Context, input json.RawMessage) (string, error) {
ctx, cancel := context.WithTimeout(ctx, d)
defer cancel()
return fn(ctx, input)
}
}Prefer combining simple functions over adding boolean parameters:
// ✗ Boolean flags multiply code paths
func Send(msg Message, retry bool, validate bool) error { ... }
// ✓ Compose behaviors
func Send(msg Message) error { ... }
func WithRetry(n int, fn func(Message) error) func(Message) error { ... }
func WithValidation(fn func(Message) error) func(Message) error { ... }
// Usage: send := WithRetry(3, WithValidation(Send))// ✗ Naked return — unclear what's being returned
func parse(s string) (result int, err error) {
result, err = strconv.Atoi(s)
return
}
// ✓ Explicit return values
func parse(s string) (int, error) {
return strconv.Atoi(s)
}Rule: Add context at every boundary. Return OR log an error — never both.
func LoadConfig(path string) (*Config, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("read config %s: %w", path, err)
}
var cfg Config
if err := json.Unmarshal(data, &cfg); err != nil {
return nil, fmt.Errorf("parse config %s: %w", path, err)
}
return &cfg, nil
}var ErrNotFound = errors.New("not found") // sentinel — package-level var
// errors.Is — value matching through chain
if errors.Is(err, ErrNotFound) { ... }
// errors.AsType — generic, no pre-declaration needed (Go 1.26)
if pathErr, ok := errors.AsType[*os.PathError](err); ok {
slog.Error("path error", "path", pathErr.Path)
}Use errgroup for first-error semantics; use errors.Join to collect all:
g, ctx := errgroup.WithContext(ctx)
g.SetLimit(10)
for _, r := range records {
g.Go(func() error { return process(ctx, r) })
}
return g.Wait()// ✓ Correct
func (s *Service) Process(ctx context.Context, req Request) error {
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
return s.client.Call(ctx, req)
}ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer cancel()
if err := run(ctx); err != nil && !errors.Is(err, context.Canceled) {
slog.Error("fatal", "error", err)
os.Exit(1)
}var wg sync.WaitGroup
for _, item := range items {
wg.Go(func() { processItem(item) }) // loop var capture safe since 1.22
}
wg.Wait()var getConfig = sync.OnceValue(func() *Config {
cfg, err := loadConfig()
if err != nil { panic(fmt.Sprintf("load config: %v", err)) }
return cfg
})
// Usage: cfg := getConfig()goleak.VerifyTestMain(m) in TestMaingoroutineleak pprof profile — GA in Go 1.26 → 1.27, no GOEXPERIMENT needed.
Scrape /debug/pprof/goroutineleak, or pprof.Lookup("goroutineleak").
It misses leaks whose primitive is reachable via a global or a runnable goroutine's
locals, so keep goleak in tests. See go-127 §3.2pi-go/
├── cmd/pi/main.go # Thin wiring only — no business logic
├── internal/
│ ├── agent/ # Core runner, tool dispatch
│ ├── config/ # Config loading
│ ├── llm/ # LLM client implementations
│ └── tools/ # Tool registry
├── .pi-go/ # Templates & runtime config
├── .vibe/compiled/ # Compiled vibe assets
├── scripts/ # Build / dev scripts
├── go.mod
├── go.sum
├── Makefile
└── .golangci.ymlpkg/ directory — this is a CLI app, not a librarymain.go only: parse config, wire deps, call run(ctx)// go.mod
tool (
github.com/golangci/golangci-lint/cmd/golangci-lint
)go tool golangci-lint run # run tracked tool
go get -u tool # upgrade all tools//go:embed all:.pi-go // "all:" required — dot-files excluded otherwise
var PiGoConfig embed.FS
//go:embed all:.vibe/compiled
var VibeCompiled embed.FSbuild:
go build -ldflags "-X main.version=$(VERSION)" -o bin/pi ./cmd/pi/
test:
go test -v -race -buildvcs ./...
lint:
go tool golangci-lint run
audit: test lint
go mod tidy -diff && go mod verifyfunc TestParseDuration(t *testing.T) {
tests := []struct {
name string
input string
want time.Duration
wantErr bool
}{
{"valid seconds", "30s", 30 * time.Second, false},
{"empty string", "", 0, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel() // always parallelise subtests
got, err := ParseDuration(tt.input)
if (err != nil) != tt.wantErr {
t.Fatalf("error = %v, wantErr %v", err, tt.wantErr)
}
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("mismatch (-want +got):\n%s", diff)
}
})
}
}t.Helper() as first line of every test helpert.Context() (Go 1.24) — auto-cancelled context, no manual setup neededgoogle/go-cmp for struct comparison over testify/assertpackage foo_test for API tests, package foo for white-boxfunc FuzzParseCommand(f *testing.F) {
f.Add("run task --model gpt-4")
f.Add("")
f.Fuzz(func(t *testing.T, input string) {
cmd, err := ParseCommand(input)
if err != nil { t.Skip() }
if got := cmd.String(); got != input {
if _, err2 := ParseCommand(got); err2 != nil {
t.Errorf("round-trip failed: %v", err2)
}
}
})
}
// Run: go test -fuzz=FuzzParseCommand -fuzztime=30s
// Failures auto-saved to testdata/fuzz/ as regression testsfunc BenchmarkProcess(b *testing.B) {
data := prepareData() // setup excluded from timing automatically
b.ReportAllocs()
for b.Loop() { // no b.ResetTimer(), no sink var needed
process(data)
}
}
// Run: go test -bench=. -benchmem
// Compare: benchstat old.txt new.txtUse synctest.Test for ANY test involving timers, tickers, timeouts, or context cancellation. Eliminates time.Sleep flakiness entirely:
func TestAgentTimeout(t *testing.T) {
synctest.Test(t, func(t *testing.T) {
ctx, cancel := context.WithTimeout(t.Context(), 5*time.Second)
defer cancel()
synctest.Sleep(5*time.Second - time.Nanosecond) // sleep + Wait (Go 1.27)
if ctx.Err() != nil {
t.Fatal("should not have timed out yet")
}
synctest.Sleep(time.Nanosecond)
if !errors.Is(ctx.Err(), context.DeadlineExceeded) {
t.Fatal("should have timed out")
}
})
}Note:
synctest.Runwas deprecated — usesynctest.Test(Go 1.25+).synctest.Sleep(d)(Go 1.27) replaces thetime.Sleep(d); synctest.Wait()pair — prefer it inside a bubble, since a baretime.Sleepleaves the wake order between the test and the code under test unpredictable when both sleep the same duration.httptest.NewTestServer(t, h)(Go 1.27) gives an in-memory HTTP server that runs in synthetic time inside a bubble and self-cleans — nodefer srv.Close().t.Attr(key, value)(Go 1.25) emits structured metadata in test output.
| Task | Old / External | ✓ Use Instead |
|---|---|---|
| Random numbers | math/rand | math/rand/v2 |
| Slice sort/search | hand-written | slices.Sort, slices.Contains |
| Map utilities | hand-written | maps.Keys, maps.Clone |
| Default value | ternary logic | cmp.Or(a, b, "default") |
| Custom iteration | returning slices | iter.Seq[V], iter.Seq2[K,V] |
| Lazy singleton | sync.Once + var | sync.OnceValue |
| Directory FS safety | path.Join | os.Root (prevents traversal) |
| Zero-value JSON omit | omitempty | omitzero tag |
| Split on last separator | strings.LastIndex + slicing | strings.CutLast / bytes.CutLast (1.27) |
| UUIDs | github.com/google/uuid | stdlib uuid (1.27); uuid.NewV7() for keys |
// iter.Seq2 for lazy DB rows
func (db *DB) Rows(ctx context.Context) iter.Seq2[Row, error] {
return func(yield func(Row, error) bool) {
rows, _ := db.Query(ctx)
defer rows.Close()
for rows.Next() {
var r Row; rows.Scan(&r)
if !yield(r, nil) { return }
}
}
}
// slices + cmp replacing manual loops
slices.SortFunc(users, func(a, b User) int { return cmp.Compare(a.Name, b.Name) })
sortedKeys := slices.Sorted(maps.Keys(m))
port := cmp.Or(envPort, flagPort, "8080")weak.Make(obj) — weak pointer for memory-efficient cachesunique.Make(v) — value interning for fast equalitycrypto/mlkem, crypto/hkdf, crypto/pbkdf2, crypto/sha3 — prefer over externalos.Root — scoped filesystem access, prevents path traversal// new(expr) — eliminates ptr() helper boilerplate
timeout := new(30 * time.Second) // *time.Duration pointing to 30s
enabled := new(true) // *bool
// errors.AsType — already shown in §2// Generic methods — a generic operation can now live on the type it belongs to.
// Restriction: interfaces cannot declare them, and they cannot satisfy an interface
// method — so keep the package-level generic func wherever the call site is an
// interface (which, per §1, is most of pi-go).
func (b Box[T]) Map[U any](f func(T) U) Box[U] { return Box[U]{v: f(b.v)} }
// Struct literal keys may be any valid field selector — promoted fields included
u := User{ID: 7, Name: "Mittens"} // was User{Base: Base{ID: 7}, Name: ...}
// Function type inference now applies in conversions and composite literals too
ops := []func([]int) int{first, last} // was {first[int], last[int]}Full detail, including removals that break a build: go-127 skill.
All Go code MUST pass golangci-lint run before commit. Run it after every change:
golangci-lint run ./... # check all packages
golangci-lint run ./internal/... # check specific subtreeIf a linter fires, fix the code — do not add //nolint without a comment explaining why the suppression is necessary.
.golangci.yml)| Category | Linters |
|---|---|
| Correctness | errcheck, govet, staticcheck, unused, ineffassign |
| Style & bugs | bodyclose, copyloopvar, durationcheck, errname, errorlint, fatcontext, misspell, nilerr, revive, unconvert, wastedassign |
| Formatters | gofmt, goimports (local prefix: github.com/dimetron/pi-go) |
check-type-assertions: true — always handle type assertion ok valuesfieldalignment and shadowindent-error-flow (guard clauses), receiver-naming, error-strings, superfluous-else, empty-block_test.go): errcheck, bodyclose, nilerr relaxedinternal/tools/: nilerr relaxed (errors returned inside result structs)internal/(lsp|cli|memory|tui)/: nilerr relaxed (callback wrappers)research/: most linters disabled (experimental code)import (
// 1. stdlib
"context"
"fmt"
// 2. third-party
"github.com/charmbracelet/bubbletea"
// 3. local (auto-grouped by goimports local-prefixes)
"github.com/dimetron/pi-go/internal/config"
)lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-go@v6
with: { go-version: '1.27' }
- uses: golangci/golangci-lint-action@v9
with: { version: v2 }
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-go@v6
with: { go-version: '1.27' }
- run: go test -v -race -coverprofile=coverage.out ./...
- run: go mod tidy -diff && go mod verifyDecision: log/slog for pi-go. Zero deps, swappable handler, context-aware.
If throughput ever matters: swap backend to zapslog.NewHandler() — no call-site changes.
// internal/logging/logging.go
func NewLogger(level slog.Level, jsonOutput bool) *slog.Logger {
opts := &slog.HandlerOptions{Level: level, AddSource: level <= slog.LevelDebug}
var h slog.Handler
if jsonOutput {
h = slog.NewJSONHandler(os.Stderr, opts) // production
} else {
h = slog.NewTextHandler(os.Stderr, opts) // development
}
return slog.New(h)
}log (stdlib old), fmt.Println, or init a global zap.Logger — depguard will catch it.With() for component-scoped fieldsslog.NewMultiHandler(h1, h2) for fan-outtype Runner struct { logger *slog.Logger }
func NewRunner(client LLMClient, logger *slog.Logger) *Runner {
return &Runner{logger: logger.With("component", "runner")}
}
// In methods
r.logger.Info("executing task", slog.String("task", task), slog.Int("iter", n))
r.logger.Error("tool failed", slog.Any("error", err), slog.String("tool", name))No Wire, no fx. Manual constructor injection wired in cmd/pi/main.go.
type clientConfig struct {
model string
timeout time.Duration
}
type Option func(*clientConfig)
func WithModel(m string) Option { return func(c *clientConfig) { c.model = m } }
func WithTimeout(d time.Duration) Option { return func(c *clientConfig) { c.timeout = d } }
func NewOpenAIClient(apiKey string, opts ...Option) *OpenAIClient {
cfg := &clientConfig{model: "gpt-4o", timeout: 30 * time.Second}
for _, o := range opts { o(cfg) }
return &OpenAIClient{apiKey: apiKey, cfg: cfg}
}func run(ctx context.Context) error {
cfg := config.Load()
logger := logging.NewLogger(cfg.LogLevel, cfg.JSONOutput)
slog.SetDefault(logger)
llmClient := llm.NewOpenAIClient(cfg.APIKey,
llm.WithModel(cfg.Model),
llm.WithTimeout(cfg.Timeout),
)
registry := tools.NewRegistry(logger, tools.WithBuiltins())
runner := agent.NewRunner(llmClient, registry, logger,
agent.WithMaxIterations(cfg.MaxIterations),
)
return runner.Run(ctx, os.Args[1:])
}type mockLLM struct{ response string; err error }
func (m *mockLLM) Complete(_ context.Context, _ string) (string, error) {
return m.response, m.err
}
func TestRunner_Execute(t *testing.T) {
r := agent.NewRunner(&mockLLM{response: "ok"}, nil, slog.Default())
if err := r.Execute(t.Context(), "task"); err != nil {
t.Fatalf("unexpected: %v", err)
}
}| Concern | Use | Avoid |
|---|---|---|
| Control flow | Guard clauses, early return | Deep nesting |
| Logic | Pure functions, value in/out | Mutating pointer args |
| Composition | Small functions + higher-order combinators | Boolean flag parameters |
| Init | Explicit constructors | init() functions |
| Returns | Explicit return values | Naked returns |
| Lint gate | golangci-lint run before commit | //nolint without justification |
| Imports | stdlib / third-party / local (3 groups) | Mixed or unsorted imports |
| Logging | log/slog | log, zap, zerolog |
| DI | manual constructors + functional options | Wire, fx |
| Error wrapping | fmt.Errorf("...: %w", err) | %v when caller needs to unwrap |
| Error type check | errors.AsType[T] (1.26) / errors.As | type assertions |
| Benchmarks | b.Loop() | for i := 0; i < b.N; i++ |
| Concurrent tests | synctest.Test + synctest.Sleep (1.27) | time.Sleep in tests |
| HTTP test server | httptest.NewTestServer(t, h) (1.27) | httptest.NewServer + defer Close() |
| Split on last separator | strings.CutLast (1.27) | strings.LastIndex + slicing |
| UUIDs | stdlib uuid (1.27) | github.com/google/uuid |
| WaitGroup | wg.Go(func(){...}) (1.25) | wg.Add(1); defer wg.Done() |
| Slice ops | slices.*, maps.* | hand-written loops |
| Randomness | math/rand/v2 | math/rand |
| Tool deps | go.mod tool directive (1.24) | tools.go blank imports |
© dimetron, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in .pi-go/skills/code-guidelines-go of dimetron/pi-go.
Open the folder on GitHubat commit 24d1f2b
Code Guidelines Go next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Code Guidelines Go this skilldimetron/pi-go | 207 | — | ~5.8k | Automated safety check: Pass | MIT | |
| Swiftui View RefactorDimillian/Skills | 4k | 5 repos | ~2k | Automated safety check: Pass | MIT | |
| RTK Rust Design Patternsrtk-ai/rtk | 83k | — | ~1.9k | Automated safety check: Pass | Apache-2.0 | |
| Architecture PatternsKartikLabhshetwar/better-shot | 2.4k | 2 repos | ~1.4k | Automated safety check: Pass | Custom licence | |
| AST Visitor Pattern for Unionsprisma/orm | 48k | — | ~830 | Automated safety check: Pass | Apache-2.0 | |
| Solidramziddin/solid-skills | 606 | — | ~2.7k | Automated safety check: Pass | None |
Dimillian/Skills
Refactor and review SwiftUI view files with strong defaults for small dedicated subviews, MV-over-MVVM data flow, stable view trees, explicit dependency injection, and correct Observation usage.
rtk-ai/rtk
Describes seven Rust design patterns for the RTK CLI filter modules, with when to use each, RTK examples, and notes on when a pattern is overkill.
KartikLabhshetwar/better-shot
Deep dive into software architecture for macOS. An agent skill from KartikLabhshetwar/better-shot.
prisma/orm
Replaces a plain TypeScript union plus switch statements with frozen subclasses and a visitor interface when several places dispatch on the same variants.
ramziddin/solid-skills
A skill your agent uses when writing code, implementing features, refactoring, planning architecture, designing systems, reviewing code, or debugging.
harperreed/dotfiles
Refactor and review SwiftUI view files for consistent structure, dependency injection, and Observation usage.
dimetron/pi-go
Record a test run, a TUI session, or any terminal command as a GIF with VHS and attach it to a GitHub PR as a release-hosted asset, never a repo commit.
dimetron/pi-go
Generate AGENTS.md files for Go, Rust, TypeScript, and Java projects.
dimetron/pi-go
A skill your agent uses whenever writing tests for Bubble Tea (charmbracelet/bubbletea) TUI applications in Go.
dimetron/pi-go
Index a folder's contents into the MemPalace semantic memory for search and retrieval.
dimetron/pi-go
Nightly sweep of the last 24h of pi-go sessions — anomalous runs, loop aborts, tool error rates, token waste, real prompt-token spend, and whether the observation and palace pipelines are still…
dimetron/pi-go
Tune macOS resource limits and sysctls for best performance with Go development, Docker/OrbStack, and Linux VMs.
Categories
Go 1.24–1.27 coding guidelines for the dimetron/pi-go AI agent runtime. Code Guidelines Go is an agent skill from dimetron/pi-go.27 coding guidelines for the dimetron/pi-go AI agent runtime.
Code Guidelines Go fits situations like: refactoring ANY Go code in pi-go; tasks that involve Design patterns; tasks that involve Refactoring.
Run `npx skills add dimetron/pi-go --skill code-guidelines-go -a claude-code`. Or copy the skill folder (.pi-go/skills/code-guidelines-go in dimetron/pi-go) into .claude/skills/code-guidelines-go in your project. Claude Code loads it when a task matches its description.
Run `npx skills add dimetron/pi-go --skill code-guidelines-go -a codex`. Or copy the skill folder (.pi-go/skills/code-guidelines-go in dimetron/pi-go) into .agents/skills/code-guidelines-go in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add dimetron/pi-go --skill code-guidelines-go -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/code-guidelines-go, .gemini/skills/code-guidelines-go, .github/skills/code-guidelines-go and .opencode/skills/code-guidelines-go in your project.
Going by SKILL.md and its folder, Code Guidelines Go needs the command-line tools its instructions call (go).
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Code Guidelines Go is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 5.8k tokens (SKILL.md is roughly 23k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Code Guidelines Go: Swiftui View Refactor (Dimillian/Skills, 4k stars), RTK Rust Design Patterns (rtk-ai/rtk, 83k stars), Architecture Patterns (KartikLabhshetwar/better-shot, 2.4k stars) and AST Visitor Pattern for Unions (prisma/orm, 48k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
dimetron (a GitHub user) maintains it in dimetron/pi-go, which has 207 GitHub stars. The repository holds 21 skills in this directory. The repository was last updated on October 1, 2026.
Source: dimetron/pi-go on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.