Skip to content
kratos-new-service logo

init env

kratos-new-service

Creates a new go-kratos microservice skeleton with clean architecture (server/service/biz/data), minimal Wire setup, HTTP + gRPC metrics, and complete project structure. Use when scaffolding new services in the brizy-go-services monorepo.

SKILL.md

Full skill instructions

<objective> Scaffold a new go-kratos microservice in the `services/` directory following clean architecture patterns. Creates minimal skeleton with: - Single cmd entry point with main.go and Wire setup - Clean architecture layers (server/​service/​biz/​data) with empty implementations - Minimal configuration (Server, Data, Metrics) - HTTP + gRPC server setup with metrics middleware - Complete Makefile with standard targets - No event handlers, publishers, or subscribers - No proto definitions (created separately) </​objective>

<quick_start> When invoked, this skill will:

  1. Ask for the service name interactively
  2. Validate the name (lowercase, alphanumeric, hyphens only)
  3. Create complete service skeleton in services/​{service-name}/
  4. Generate Wire dependency injection code
  5. Create initial configs/​config.yaml

The service will be ready to build but will need proto definitions added separately. </​quick_start>

<workflow> ## Step 1: Get and Validate Service Name

Ask the user for the service name:

What is the name of the new service?

Requirements:
- Lowercase letters, numbers, and hyphens only
- Must be a valid Go module name
- Will be used for directory name, module path, and service identification

Example: auth, user-management, notification-service

Validate the input:

  • Only lowercase letters (a-z), numbers (0-9), and hyphens (-) allowed
  • No consecutive hyphens
  • Cannot start or end with a hyphen
  • Length: 3-50 characters

If invalid, explain the issue and ask again.

Step 2: Check for Conflicts

Verify that services/​{service-name}/ does not already exist:

ls services/​{service-name} 2>/​dev/​null

If it exists, inform the user and stop. Do not overwrite existing services.

Step 3: Create Directory Structure

Create the complete directory structure:

mkdir -p services/​{service-name}/​cmd/​{service-name}
mkdir -p services/​{service-name}/​internal/​biz
mkdir -p services/​{service-name}/​internal/​data/​model
mkdir -p services/​{service-name}/​internal/​data/​repo
mkdir -p services/​{service-name}/​internal/​service
mkdir -p services/​{service-name}/​internal/​server
mkdir -p services/​{service-name}/​internal/​conf
mkdir -p services/​{service-name}/​configs
mkdir -p services/​{service-name}/​bin

Step 4: Create Configuration Files

4.1 Create internal/​conf/​conf.proto

syntax = "proto3";

package conf;

option go_package = "services/​{service-name}/​internal/​conf;conf";

import "google/​protobuf/​duration.proto";

message Bootstrap {
  Server server = 1;
  Data data = 2;
  Metrics metrics = 3;
}

message Server {
  message HTTP {
    string network = 1;
    string addr = 2;
    google.protobuf.Duration timeout = 3;
  }
  message GRPC {
    string network = 1;
    string addr = 2;
    google.protobuf.Duration timeout = 3;
  }
  HTTP http = 1;
  GRPC grpc = 2;
}

message Data {
  message Database {
    string driver = 1;
    string source = 2;
  }
  Database database = 1;
}

message Metrics {
  bool enabled = 1;
  string service_name = 2;
  string path = 3;
  bool include_runtime = 4;
}

4.2 Create configs/​config.yaml

server:
  http:
    addr: 0.0.0.0:8000
    timeout: 5s
  grpc:
    addr: 0.0.0.0:9000
    timeout: 5s
data:
  database:
    driver: postgres
    source: postgres://user:password@localhost:5432/​{service-name}?sslmode=disable
metrics:
  enabled: true
  path: /​metrics
  include_runtime: true

Replace {service-name} with the actual service name in the YAML.

Step 5: Create Data Layer Files

5.1 Create internal/​data/​data.go

package data

import (
	"github.com/​go-kratos/​kratos/​v2/​log"
	"github.com/​google/​wire"
	"services/​{service-name}/​internal/​conf"
)

// ProviderSet is data providers.
var ProviderSet = wire.NewSet(
	NewData,
)

// Data encapsulates all data access dependencies.
type Data struct {
	log *log.Helper
	// db *gorm.DB - uncomment when adding GORM
}

// NewData creates a new Data instance.
func NewData(c *conf.Data, logger log.Logger) (*Data, func(), error) {
	logHelper := log.NewHelper(log.With(logger, "module", "data"))

	d := &Data{
		log: logHelper,
	}

	cleanup := func() {
		logHelper.Info("closing data resources")
	}

	return d, cleanup, nil
}

Replace {service-name} with the actual service name.

Step 6: Create Business Logic Layer Files

6.1 Create internal/​biz/​interfaces.go

package biz

// Repository interfaces will be defined here
// Example:
// type ExampleRepo interface {
// 	Save(ctx context.Context, example *Example) error
// 	FindByID(ctx context.Context, id int64) (*Example, error)
// }

6.2 Create internal/​biz/​biz.go

package biz

import (
	"github.com/​go-kratos/​kratos/​v2/​log"
	"github.com/​google/​wire"
)

// ProviderSet is business logic providers.
var ProviderSet = wire.NewSet()

Step 7: Create Service Layer Files

7.1 Create internal/​service/​service.go

package service

import (
	"github.com/​google/​wire"
	"services/​{service-name}/​internal/​biz"
)

// ProviderSet is service providers.
var ProviderSet = wire.NewSet(
	NewService,
)

// Service encapsulates business logic dependencies.
type Service struct {
	log *log.Helper
}

// NewService creates a new Service instance.
func NewService(logger log.Logger) *Service {
	return &Service{
		log: log.NewHelper(log.With(logger, "module", "service")),
	}
}

Replace {service-name} with the actual service name.

Step 8: Create Server Layer Files

8.1 Create internal/​server/​http.go

package server

import (
	"github.com/​go-kratos/​kratos/​v2/​log"
	"github.com/​go-kratos/​kratos/​v2/​middleware/​logging"
	"github.com/​go-kratos/​kratos/​v2/​middleware/​recovery"
	"github.com/​go-kratos/​kratos/​v2/​transport/​http"
	"platform/​metrics"
	"services/​{service-name}/​internal/​conf"
	"services/​{service-name}/​internal/​service"
)

// NewHTTPServer creates a new HTTP server.
func NewHTTPServer(
	c *conf.Server,
	logger log.Logger,
	svc *service.Service,
	metricsRegistry *metrics.Registry,
) *http.Server {
	var opts = []http.ServerOption{
		http.Middleware(
			recovery.Recovery(),
			logging.Server(logger),
			metrics.HTTPMiddleware(metricsRegistry),
		),
	}
	if c.Http.Network != "" {
		opts = append(opts, http.Network(c.Http.Network))
	}
	if c.Http.Addr != "" {
		opts = append(opts, http.Address(c.Http.Addr))
	}
	if c.Http.Timeout != nil {
		opts = append(opts, http.Timeout(c.Http.Timeout.AsDuration()))
	}
	srv := http.NewServer(opts...)

	// Register service handlers here
	// Example:
	// v1.RegisterExampleServiceHTTPServer(srv, svc)

	return srv
}

Replace {service-name} with the actual service name.

8.2 Create internal/​server/​grpc.go

package server

import (
	"github.com/​go-kratos/​kratos/​v2/​log"
	"github.com/​go-kratos/​kratos/​v2/​middleware/​logging"
	"github.com/​go-kratos/​kratos/​v2/​middleware/​recovery"
	"github.com/​go-kratos/​kratos/​v2/​transport/​grpc"
	"platform/​metrics"
	"services/​{service-name}/​internal/​conf"
	"services/​{service-name}/​internal/​service"
)

// NewGRPCServer creates a new gRPC server.
func NewGRPCServer(
	c *conf.Server,
	logger log.Logger,
	svc *service.Service,
	metricsRegistry *metrics.Registry,
) *grpc.Server {
	var opts = []grpc.ServerOption{
		grpc.Middleware(
			recovery.Recovery(),
			logging.Server(logger),
			metrics.GRPCMiddleware(metricsRegistry),
		),
	}
	if c.Grpc.Network != "" {
		opts = append(opts, grpc.Network(c.Grpc.Network))
	}
	if c.Grpc.Addr != "" {
		opts = append(opts, grpc.Address(c.Grpc.Addr))
	}
	if c.Grpc.Timeout != nil {
		opts = append(opts, grpc.Timeout(c.Grpc.Timeout.AsDuration()))
	}
	srv := grpc.NewServer(opts...)

	// Register service handlers here
	// Example:
	// v1.RegisterExampleServiceServer(srv, svc)

	return srv
}

Replace {service-name} with the actual service name.

8.3 Create internal/​server/​server.go

package server

import (
	"github.com/​google/​wire"
)

// ProviderSet is server providers.
var ProviderSet = wire.NewSet(
	NewHTTPServer,
	NewGRPCServer,
	NewMetricsRegistry,
)

8.4 Create internal/​server/​metrics.go

package server

import (
	"platform/​metrics"
	"services/​{service-name}/​internal/​conf"
)

// NewMetricsRegistry creates a new metrics registry.
func NewMetricsRegistry(c *conf.Metrics) *metrics.Registry {
	if !c.Enabled {
		return nil
	}

	return metrics.NewRegistry(c.ServiceName, c.IncludeRuntime)
}

Replace {service-name} with the actual service name.

Step 9: Create Command Layer Files

9.1 Create cmd/​{service-name}/​main.go

package main

import (
	"flag"
	"os"

	"github.com/​go-kratos/​kratos/​v2"
	"github.com/​go-kratos/​kratos/​v2/​config"
	"github.com/​go-kratos/​kratos/​v2/​config/​file"
	"github.com/​go-kratos/​kratos/​v2/​log"
	"github.com/​go-kratos/​kratos/​v2/​transport/​http"
	"services/​{service-name}/​internal/​conf"
)

// go build -ldflags "-X main.Version=x.y.z"
var (
	// Name is the name of the compiled software.
	Name string = "symbol-service"
	// Version is the version of the compiled software.
	Version string = "1.0"
	// configFile is the config flag.
	configFile string

	id, _ = os.Hostname()
)

func init() {
	flag.StringVar(&configFile, "conf", "configs/​config.yaml", "config path, eg: --conf config.yaml")
}

var buildInfo = build.NewBuildInfo(Name, Version)

func main() {
	flag.Parse()
	logger := log.With(log.NewStdLogger(os.Stdout),
		"ts", log.DefaultTimestamp,
		"caller", log.DefaultCaller,
		"service.name", "{service-name}",
	)

	c := config.New(
		config.WithSource(
			file.NewSource(flagconf),
		),
	)
	defer c.Close()

	if err := c.Load(); err != nil {
		panic(err)
	}

	var bc conf.Bootstrap
	if err := c.Scan(&bc); err != nil {
		panic(err)
	}

	app, cleanup, err := wireApp(buildInfo, bc.Server, bc.Data, bc.Metrics, logger)
	if err != nil {
		panic(err)
	}
	defer cleanup()

	// Start and wait for stop signal
	if err := app.Run(); err != nil {
		panic(err)
	}
}

func newApp(logger log.Logger, hs *http.Server, gs *grpc.Server) *kratos.App {
	return kratos.New(
		kratos.ID(id),
		kratos.Name(Name),
		kratos.Version(Version),
		kratos.Metadata(map[string]string{}),
		kratos.Logger(logger),
		kratos.Server(
			gs,
			hs,
		),
	)
}

Replace {service-name} with the actual service name.

9.2 Create cmd/​{service-name}/​wire.go

//go:build wireinject
// +build wireinject

package main

import (
	platform_build_info "platform/​build"
	platform_logger "platform/​logger"
	
	"github.com/​go-kratos/​kratos/​v2"
	"github.com/​go-kratos/​kratos/​v2/​log"
	"github.com/​google/​wire"
	"services/​{service-name}/​internal/​biz"
	"services/​{service-name}/​internal/​conf"
	"services/​{service-name}/​internal/​data"
	"services/​{service-name}/​internal/​server"
	"services/​{service-name}/​internal/​service"
)

// wireApp builds the application with dependency injection.
func wireApp(*platform_build_info.ServiceBuildInfo, *conf.Data, *conf.Metrics, log.Logger) (*kratos.App, func(), error) {
	panic(wire.Build(
		platform_logger.ProviderSet,
		server.ProviderSet,
		service.ProviderSet,
		biz.ProviderSet,
		data.ProviderSet,
		newApp,
	))
}

Replace {service-name} with the actual service name.

Step 10: Create Build Configuration Files

10.1 Create go.mod

module services/​{service-name}

go 1.25.0

require (
    github.com/​envoyproxy/​protoc-gen-validate v1.3.0
    github.com/​go-kratos/​kratos/​contrib/​middleware/​validate/​v2 v2.0.0-20251217105121-fb8e43efb207
    github.com/​go-kratos/​kratos/​v2 v2.9.2
    github.com/​go-playground/​validator/​v10 v10.30.1
    github.com/​google/​wire v0.7.0
    github.com/​gorilla/​handlers v1.5.2
    github.com/​stretchr/​testify v1.11.1
    go.uber.org/​automaxprocs v1.6.0
    google.golang.org/​protobuf v1.36.11
    gorm.io/​driver/​mysql v1.6.0
    gorm.io/​driver/​sqlite v1.6.0
    gorm.io/​gorm v1.31.1
)

Replace {service-name} with the actual service name.

10.2 Create Makefile

GOHOSTOS:=$(shell go env GOHOSTOS)
GOPATH:=$(shell go env GOPATH)
VERSION=$(shell git describe --tags --always)

ifeq ($(GOHOSTOS), windows)
	#the `find.exe` is different from `find` in bash/​shell.
	#to see https://docs.microsoft.com/​en-us/​windows-server/​administration/​windows-commands/​find.
	#changed to use git-bash.exe to run find cli or other cli friendly, caused of every developer has a Git.
	#Git_Bash= $(subst cmd\,bin\bash.exe,$(dir $(shell where git)))
	Git_Bash=$(subst \,/, $(subst cmd\,bin\bash.exe,$(dir $(shell where git))))
	INTERNAL_PROTO_FILES=$(shell $(Git_Bash) -c "find internal -name *.proto")
	API_PROTO_FILES=$(shell $(Git_Bash) -c "find api -name *.proto")
else
	INTERNAL_PROTO_FILES=$(shell find internal -name *.proto)
	API_PROTO_FILES=$(shell find api -name *.proto)
endif

.PHONY: init config api build generate all test coverage help

APP_NAME := symbols
BIN_DIR := bin

# init env
init:
	go install google.golang.org/​protobuf/​cmd/​protoc-gen-go@latest
	go install google.golang.org/​grpc/​cmd/​protoc-gen-go-grpc@latest
	go install github.com/​go-kratos/​kratos/​cmd/​kratos/​v2@latest
	go install github.com/​go-kratos/​kratos/​cmd/​protoc-gen-go-http/​v2@latest
	go install github.com/​google/​gnostic/​cmd/​protoc-gen-openapi@latest
	go install github.com/​google/​wire/​cmd/​wire@latest
	go install github.com/​envoyproxy/​protoc-gen-validate@latest

# generate internal proto
config:
	buf dep update
	buf lint
	buf format -w
	buf generate

# build
build: service worker

service: generate
	go build -o $(BIN_DIR)/​$(APP_NAME) ./​cmd/​$(APP_NAME)

# generate wire files
generate:
	wire ./​cmd/​symbols
	go mod tidy

# generate all
all:
	make config;
	make generate;

# run unit tests
test:
	go test -v -race -coverprofile=coverage.out ./​internal/​...

# generate coverage report
coverage:
	go test -v -coverprofile=coverage.out ./​...
	go tool cover -html=coverage.out -o coverage.html
	@echo "Coverage report generated: coverage.html"

# show help
help:
	@echo ''
	@echo 'Usage:'
	@echo ' make [target]'
	@echo ''
	@echo 'Targets:'
	@awk '/^[a-zA-Z\-\_0-9]+:/ { \
	helpMessage = match(lastLine, /^# (.*)/); \
		if (helpMessage) { \
			helpCommand = substr($$1, 0, index($$1, ":")); \
			helpMessage = substr(lastLine, RSTART + 2, RLENGTH); \
			printf "\033[36m%-22s\033[0m %s\n", helpCommand,helpMessage; \
		} \
	} \
	{ lastLine = $$0 }' $(MAKEFILE_LIST)

.DEFAULT_GOAL := help

Replace {service-name} with the actual service name.

10.3 Create internal/​conf/​buf.yaml

version: v2
modules:
  - path: internal/​conf/
deps:
  - buf.build/​envoyproxy/​protoc-gen-validate
lint:
  use:
    - STANDARD
breaking:
  use:
    - FILE

10.4 Create internal/​conf/​buf.gen.yaml

version: v2
managed:
  enabled: true

plugins:
  # Generate Go protobuf code for service configuration schema
  # Used to define strongly-typed config loaded from YAML at runtime
  - remote: buf.build/​protocolbuffers/​go
    out: internal/​conf/​gen
    opt: paths=source_relative
  # Generate validation code from protoc-gen-validate annotations
  - local: protoc-gen-validate
    out: internal/​conf/​gen
    opt: paths=source_relative,lang=go
inputs:
  - directory: internal/​conf

Replace {service-name} with the actual service name.

10.5 Create .gitignore

# Binaries
bin/

# Wire generated
wire_gen.go

# Test coverage
coverage.out
coverage.html

# IDE
.idea/
.vscode/
*.swp
*.swo
*~

# OS
.DS_Store
Thumbs.db

10.6 Create README.md

# {Service Name}

{Brief description of what this service does}

## Architecture

This service follows clean architecture with the following layers:

- **cmd/​** - Application entry point and dependency injection (Wire)
- **internal/​server/​** - HTTP and gRPC server setup
- **internal/​service/​** - Service handlers (implements proto service interfaces)
- **internal/​biz/​** - Business logic and use cases
- **internal/​data/​** - Data access layer (repositories, database)
- **internal/​conf/​** - Configuration protobuf definitions

## Development

### Prerequisites

```bash
make init

Generate Wire Code

make generate

Build

make build

Run

./​bin/​{service-name} -conf configs/​config.yaml

Test

make test

Coverage

make coverage

Configuration

Configuration is defined in internal/​conf/​conf.proto and loaded from configs/​config.yaml.

Server

  • HTTP server on port 8000
  • gRPC server on port 9000

Metrics

Prometheus metrics exposed at /​metrics:

  • HTTP request metrics
  • gRPC request metrics
  • Go runtime metrics (if enabled)

API

Proto definitions should be added to api/​service/​{service-name}/​v1/ in the monorepo root.

After defining protos:

  1. Run make contracts-generate from monorepo root
  2. Import generated code in service handlers
  3. Register handlers in internal/​server/​http.go and internal/​server/​grpc.go

Adding Features

Add a new use case

  1. Define repository interface in internal/​biz/​interfaces.go
  2. Create use case in internal/​biz/​my_usecase.go
  3. Add to biz.ProviderSet
  4. Implement repository in internal/​data/​repo/​my_repo.go
  5. Add to data.ProviderSet
  6. Inject into service layer

Add database

  1. Uncomment GORM in internal/​data/​data.go
  2. Add models in internal/​data/​model/
  3. Add repositories in internal/​data/​repo/
  4. Update config to include database connection

Replace `{Service Name}` and `{service-name}` with the actual service name.

## Step 11: Generate Wire Code

Navigate to the cmd directory and generate Wire code:

```bash
cd services/​{service-name}/​cmd/​{service-name}
GOWORK=off go generate

This will create wire_gen.go with the dependency injection graph.

Step 12: Verify Build

Build the service to verify everything is wired correctly:

cd services/​{service-name}
make build

If there are any import or compilation errors, fix them before proceeding.

Step 13: Summary

Inform the user of what was created:

✓ Created new service: {service-name}
✓ Location: services/​{service-name}/
✓ Structure: Clean architecture with server/​service/​biz/​data layers
✓ Config: Complete config with Server, Data, Metrics
✓ Wire: Dependency injection configured and generated
✓ Metrics: HTTP and gRPC metrics enabled
✓ Build: Makefile with all standard targets

Next steps:
1. Define proto API in api/​service/​{service-name}/​v1/
2. Run 'make contracts-generate' from monorepo root
3. Implement service handlers in internal/​service/
4. Add business logic in internal/​biz/
5. Implement repositories in internal/​data/

The service is ready to build and run, but needs proto definitions to be useful.

</​workflow>

<success_criteria> Service skeleton is complete when:

  • Service name validated (lowercase, alphanumeric, hyphens only)
  • No conflicts with existing services
  • Complete directory structure created
  • All layer files created with correct imports
  • Configuration files in place (conf.proto, config.yaml)
  • Wire setup complete (wire.go and wire_gen.go generated)
  • Metrics registry configured in server layer
  • HTTP and gRPC servers have metrics middleware
  • Makefile has all standard targets
  • Service builds successfully with make build
  • All placeholder {service-name} replaced with actual service name
  • README.md provides clear next steps
  • No event handlers, publishers, or subscribers included
  • No proto definitions created (user adds separately) </​success_criteria>

More skills from majiayu000

xiaohongshu logo
majiayu000/claude-arsenal

xiaohongshu

xiaohongshu

286 148
View
agent-task-conductor logo
majiayu000/claude-skill-registry

agent-task-conductor

Conduct multi-agent task orchestration and workflow coordination.

663 1
View
conductor-setup logo
majiayu000/claude-skill-registry

conductor-setup

Initialize project with Conductor artifacts (product definition,

663 1
View
animation-designer logo
majiayu000/claude-skill-registry

animation-designer

Expert in web animations, transitions, and motion design using Framer Motion and CSS

663 1
View
diagramming logo
majiayu000/claude-skill-registry

diagramming

Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...

663 1
View
h3-pg logo
majiayu000/claude-skill-registry-data

h3-pg

PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.

23 1
View
conductor-development logo
majiayu000/claude-skill-registry

conductor-development

Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...

663 1
View
conductor-status logo
majiayu000/claude-skill-registry

conductor-status

Display project status, active tracks, and next actions

663 1
View
dockerization logo
majiayu000/claude-skill-registry

dockerization

Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.

663 1
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View