.claude/skills/go-reviewer/SKILL.md
| name | description | |------|-------------| | go-reviewer | Review Go code changes for idiomatic patterns, concurrency safety, memory optimization, and test quality specific to Anytype Heart. Use when implementing Go features, modifying existing code, or creating new modules. Triggers on requests like "review this code", "check for issues", or after implementing features. | # Go Code Review Agent - Anytype Heart You are a Go specialist reviewing code in the Anytype Heart codebase. Apply exce
npx skillsauth add anyproto/anytype-heart .claude/skills/go-reviewerInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
| name | description | |------|-------------| | go-reviewer | Review Go code changes for idiomatic patterns, concurrency safety, memory optimization, and test quality specific to Anytype Heart. Use when implementing Go features, modifying existing code, or creating new modules. Triggers on requests like "review this code", "check for issues", or after implementing features. |
You are a Go specialist reviewing code in the Anytype Heart codebase. Apply exceptionally high standards for idiomatic, safe, and performant Go code following established patterns in this repository.
git diff or read provided filesCName, Init(), Run(), Close() patternsWork through each checklist relevant to the changed code.
Required Pattern - Background goroutines MUST use component context:
// CORRECT - core/block/service.go pattern
func (s *Service) Init(a *app.App) error {
s.componentCtx, s.componentCtxCancel = context.WithCancel(context.Background())
return nil
}
func (s *Service) Run(ctx context.Context) error {
go func() {
for {
select {
case <-s.componentCtx.Done():
return // Clean exit on shutdown
case item := <-s.workChan:
// process
}
}
}()
return nil
}
func (s *Service) Close(_ context.Context) error {
s.componentCtxCancel() // Signal goroutines to exit
return nil
}
Check for:
go func() has corresponding shutdown mechanismRequired Pattern - Always cancel derived contexts:
// CORRECT - space/service.go:267 pattern
timeoutCtx, cancel := context.WithTimeout(ctx, deadline)
defer cancel() // ALWAYS defer cancel
err := s.operation(timeoutCtx)
Check for:
context.WithTimeout / context.WithCancel paired with defer cancel()componentCtx)Required Pattern - Always defer unlock:
// CORRECT - standard pattern throughout codebase
func (s *service) Method() {
s.mu.Lock()
defer s.mu.Unlock()
// critical section
}
// CORRECT - Using helper (util/mutex/convenience.go)
result := mutex.WithLock(s.mu, func() T {
return s.protectedOp()
})
Check for:
Lock() immediately followed by defer Unlock()Required Pattern - Atomic booleans for shutdown flags:
// CORRECT - space/service.go:172 pattern
type service struct {
isClosing atomic.Bool
}
func (s *service) Method() error {
if s.isClosing.Load() {
return ErrServiceClosing
}
// ...
}
func (s *service) Close(ctx context.Context) error {
s.isClosing.Store(true)
// cleanup...
}
Check for:
atomic.Bool, not regular bool with mutexatomic.Uint64 / atomic.Int64Required Pattern - Select with context cancellation:
// CORRECT - space/spacecore/keyvalueobserver/observer.go pattern
for {
select {
case <-ctx.Done():
return
case item := <-ch:
// process
case <-time.After(delay):
delay *= 2 // backoff
}
}
Check for:
Required Pattern - Parallel shutdown with WaitGroup:
// CORRECT - space/service.go:502-513 pattern
func (s *service) Close(ctx context.Context) error {
s.mu.Lock()
items := make([]Item, 0, len(s.items))
for _, item := range s.items {
items = append(items, item)
}
s.mu.Unlock() // Release lock before goroutines
wg := sync.WaitGroup{}
for _, item := range items {
wg.Add(1)
go func(item Item) { // Pass as parameter, not closure capture
defer wg.Done()
item.Close(ctx)
}(item)
}
wg.Wait()
return nil
}
Check for:
wg.Add() called before go func()defer wg.Done() at start of goroutineRequired Pattern - app.Component interface:
// CORRECT - standard pattern
const CName = "package.service"
type Service interface {
Method() error
app.Component
}
type service struct {
dep1 Dependency1
dep2 Dependency2
}
func New() Service {
return &service{}
}
func (s *service) Init(a *app.App) error {
s.dep1 = app.MustComponent[Dependency1](a)
s.dep2 = app.MustComponent[Dependency2](a)
return nil
}
func (s *service) Name() string {
return CName
}
Check for:
CName constant defined at package levelNew() returns interface type, not concrete struct pointerInit(), not constructorName() returns CNameRequired Pattern - Always use cache.Do for SmartBlock access:
// CORRECT - core/block/cache/cache.go pattern
err := cache.Do(s.picker, objectId, func(sb basic.CommonOperations) error {
state := sb.NewState()
// operations on locked object
return sb.Apply(state)
})
// CORRECT - With context
err := cache.DoContext(s.picker, ctx, objectId, func(sb smartblock.SmartBlock) error {
// ...
})
Check for:
Lock()/Unlock() on SmartBlockRequired Pattern - Wrap errors with context:
// CORRECT
if err != nil {
return fmt.Errorf("operation description: %w", err)
}
// CORRECT - Error comparison
if errors.Is(err, ErrNotFound) {
// handle specific error
}
// CORRECT - Custom errors (core/acl/errors.go pattern)
var (
ErrNotFound = errors.New("not found")
ErrInvalidInput = errors.New("invalid input")
)
Check for:
fmt.Errorf("context: %w", err)errors.Is() for comparison, never ==varRequired Pattern - Small focused interfaces:
// CORRECT - Define interfaces for dependencies
type nodeConfGetter interface {
GetNodeConf() nodeconf.Configuration
}
// CORRECT - Compose with app.Component for registration
type Service interface {
app.Component
Operation() error
}
Check for:
Required Pattern - Pool reusable objects in hot paths:
// CORRECT - util/pbtypes/copy.go pattern
var bytesPool = &sync.Pool{
New: func() interface{} {
return []byte{}
},
}
func ProcessData(in []byte) []byte {
buf := bytesPool.Get().([]byte)
defer bytesPool.Put(buf)
if cap(buf) < len(in) {
buf = make([]byte, 0, len(in)*2) // Grow with headroom
}
// use buf
return result
}
Check for:
Required Pattern - Use arena for JSON operations:
// CORRECT - pkg/lib/localstore/objectstore/spaceindex/store.go pattern
type store struct {
arenaPool *anyenc.ArenaPool
}
func (s *store) Method() {
arena := s.arenaPool.Get()
defer s.arenaPool.Put(arena)
// use arena for encoding
}
Check for:
anyenc.ArenaPool or fastjson.ArenaPool for JSON operationsRequired Pattern - Pre-allocate when size is known:
// CORRECT - Known exact size
result := make([]Item, len(source))
// CORRECT - Known capacity estimate
result := make([]Item, 0, len(source))
// CORRECT - Map capacity
cache := make(map[string]Value, expectedSize)
Check for:
make([]T, 0, n) when length unknown but capacity estimablemake([]T, n) when exact length knownRequired Pattern - Use Builder for string concatenation:
// CORRECT
var b strings.Builder
b.WriteString("prefix")
b.WriteString(variable)
result := b.String()
// WRONG
result := "prefix" + variable + suffix // Multiple allocations
Check for:
+ operator in loops for string buildingRequired Pattern - Use bufferpool for file I/O:
// CORRECT - util/bufferpool pattern
pool := bufferpool.NewPool()
buf := pool.Get()
defer buf.Close() // Returns to pool
Check for:
Required Pattern:
// CORRECT
func TestOperation(t *testing.T) {
tests := []struct {
name string
input Input
want Output
wantErr error
}{
{"valid input", Input{...}, Output{...}, nil},
{"invalid input", Input{...}, Output{}, ErrInvalid},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := Operation(tt.input)
if tt.wantErr != nil {
require.ErrorIs(t, err, tt.wantErr)
return
}
require.NoError(t, err)
assert.Equal(t, tt.want, got)
})
}
}
Check for:
t.Run() for subtestsRequired Pattern:
// CORRECT - core/block/detailservice/service_test.go pattern
type fixture struct {
Service
mockDep1 *mock_dep.MockDep1
mockDep2 *mock_dep.MockDep2
}
func newFixture(t *testing.T) *fixture {
mockDep1 := mock_dep.NewMockDep1(t)
mockDep2 := mock_dep.NewMockDep2(t)
// Setup default expectations
mockDep1.EXPECT().Method().Return(nil).Maybe()
svc := &service{
dep1: mockDep1,
dep2: mockDep2,
}
return &fixture{svc, mockDep1, mockDep2}
}
Check for:
newFixture(t *testing.T) constructor.Maybe()t for automatic cleanupRequired Pattern:
// CORRECT - testify mock
mock.EXPECT().Method(mock.Anything).Return(value)
mock.EXPECT().Method(specificArg).Return(value).Times(1)
// CORRECT - gomock
ctrl := gomock.NewController(t)
mock := mock_pkg.NewMockInterface(ctrl)
mock.EXPECT().Method(gomock.Any()).Return(value)
Check for:
mock.Anything / gomock.Any() for non-essential args.Times() / .Once() when call count matterst)Required Pattern - Use testify consistently:
// CORRECT
require.NoError(t, err) // Fatal on error
require.NotNil(t, result) // Fatal if nil
assert.Equal(t, expected, actual) // Continue on failure
assert.True(t, condition)
assert.Contains(t, slice, element)
Check for:
require for preconditions (test cannot continue)assert for validations (test can continue)if err != nil { t.Fatal(err) } - use require.NoErrorEvery component MUST have a documentation header (comment block after package with Name:, Scope:, ## Responsibility, etc.). Only report mismatches and missing documentation.
package X lineReport only mismatches - don't list things that are correct:
Missing documentation:
### [High] Missing Component Documentation
**Location**: `path/to/file.go`
**Problem**: Component lacks required documentation header.
**Resolution**: Use document-component agent to generate documentation.
Documentation mismatch:
### [Medium] Documentation Mismatch: {specific issue}
**Documented**: {what documentation says}
**Actual Code**: {what code actually does}
**Resolution**: Update code to match docs OR update docs to match code (specify which)
Do NOT report:
For each issue found, report:
### [Severity] Issue Title
**Location**: `path/to/file.go:line`
**Problem**: Clear description of what's wrong.
**Current Code**:
```go
// problematic code
Suggested Fix:
// corrected code following codebase patterns
Reference: Similar pattern at reference/file.go:line (optional)
## Severity Levels
- **Critical**: Goroutine leaks, race conditions, deadlocks, data corruption, security issues
- **High**: Memory leaks, performance issues in hot paths, broken functionality, missing error handling
- **Medium**: Anti-patterns, style inconsistencies, suboptimal patterns, test gaps
- **Low**: Minor style issues, documentation, minor optimizations
## Anti-Patterns Quick Reference
| Anti-Pattern | Correct Pattern | Reference File |
|--------------|-----------------|----------------|
| `err == ErrX` | `errors.Is(err, ErrX)` | core/acl/errors.go |
| Manual SmartBlock lock | `cache.Do(picker, id, func...)` | core/block/cache/cache.go |
| `go func() { ... }()` without context | Check `ctx.Done()` in loop | space/service.go:562-580 |
| Lock held during I/O | Unlock before blocking | core/subscription/service.go:498-509 |
| `+ ` string concat in loop | `strings.Builder` | util/strutil/str.go |
| `make([]T, 0)` in hot path | Pre-allocate or use pool | util/pbtypes/copy.go |
| `&bytes.Buffer{}` in loop | Use bufferpool | util/bufferpool/pool.go |
| Loop var in goroutine closure | Pass as function argument | space/service.go:505-511 |
| `New() *serviceImpl` | `New() ServiceInterface` | All services |
| Context stored in struct | Pass as method parameter | - |
## Codebase-Specific Notes
1. **Any-Sync Integration**: Space operations involve CRDT sync - be careful with concurrent modifications
2. **Object IDs**: Always validate object IDs exist before operations
3. **Tech Space**: Account-level data stored separately - different access patterns
4. **Message Batching**: Use `mb.MB` for decoupling producers/consumers (core/subscription pattern)
5. **File Queue**: Actor model in core/files/filesync/filequeue - no locks in main loop
development
Maintainer-only workflow for handling GitHub Secret Scanning alerts on OpenClaw. Use when Codex needs to triage, redact, clean up, and resolve secret leakage found in issue comments, issue bodies, PR comments, or other GitHub content.
development
Maintainer workflow for OpenClaw releases, prereleases, changelog release notes, and publish validation. Use when Codex needs to prepare or verify stable or beta release steps, align version naming, assemble release notes, check release auth requirements, or validate publish-time commands and artifacts.
development
Run, watch, debug, and extend OpenClaw QA testing with qa-lab and qa-channel. Use when Codex needs to execute the repo-backed QA suite, inspect live QA artifacts, debug failing scenarios, add new QA scenarios, or explain the OpenClaw QA workflow. Prefer the live OpenAI lane with regular openai/gpt-5.4 in fast mode; do not use gpt-5.4-pro or gpt-5.4-mini unless the user explicitly overrides that policy.
development
End-to-end Parallels smoke, upgrade, and rerun workflow for OpenClaw across macOS, Windows, and Linux guests. Use when Codex needs to run, rerun, debug, or interpret VM-based install, onboarding, gateway smoke tests, latest-release-to-main upgrade checks, fresh snapshot retests, or optional Discord roundtrip verification under Parallels.