chore: import upstream snapshot with attribution
govulncheck / govulncheck (push) Has been cancelled
Lint / golangci-lint (push) Has been cancelled
Run Tests / Unit Tests (push) Has been cancelled
Run Tests / Etcd Integration Tests (push) Has been cancelled
Harness (E2E) / Harnesses (mock LLM) (push) Has been cancelled
Harness (E2E) / Provider harnesses (live LLM conformance) (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 12:40:33 +08:00
commit e071084ebe
982 changed files with 160368 additions and 0 deletions
+122
View File
@@ -0,0 +1,122 @@
package template
var (
ApiProtoSRV = `syntax = "proto3";
package {{dehyphen .Alias}};
option go_package = "./proto;{{dehyphen .Alias}}";
service {{title .Alias}} {
rpc Health(HealthRequest) returns (HealthResponse) {}
rpc Endpoint(EndpointRequest) returns (EndpointResponse) {}
}
message HealthRequest {}
message HealthResponse {
string status = 1;
int64 uptime = 2;
}
message EndpointRequest {
string method = 1;
string path = 2;
string body = 3;
map<string, string> headers = 4;
}
message EndpointResponse {
int32 status_code = 1;
string body = 2;
map<string, string> headers = 3;
}
`
ApiHandlerSRV = `package handler
import (
"context"
"encoding/json"
"fmt"
"net/http"
"time"
log "go-micro.dev/v6/logger"
pb "{{.Dir}}/proto"
)
type {{title .Alias}} struct {
started time.Time
routes map[string]http.HandlerFunc
}
func New() *{{title .Alias}} {
h := &{{title .Alias}}{
started: time.Now(),
routes: make(map[string]http.HandlerFunc),
}
h.registerRoutes()
return h
}
func (h *{{title .Alias}}) registerRoutes() {
h.routes["GET /hello"] = func(w http.ResponseWriter, r *http.Request) {
name := r.URL.Query().Get("name")
if name == "" {
name = "World"
}
json.NewEncoder(w).Encode(map[string]string{
"message": fmt.Sprintf("Hello %s", name),
})
}
}
// Health returns the service health status and uptime.
//
// @example {}
func (h *{{title .Alias}}) Health(ctx context.Context, req *pb.HealthRequest, rsp *pb.HealthResponse) error {
rsp.Status = "ok"
rsp.Uptime = int64(time.Since(h.started).Seconds())
return nil
}
// Endpoint handles proxied HTTP requests. The method and path fields
// select the route; body and headers are forwarded.
//
// @example {"method": "GET", "path": "/hello", "body": "", "headers": {}}
func (h *{{title .Alias}}) Endpoint(ctx context.Context, req *pb.EndpointRequest, rsp *pb.EndpointResponse) error {
key := fmt.Sprintf("%s %s", req.Method, req.Path)
handler, ok := h.routes[key]
if !ok {
log.Infof("Route not found: %s", key)
rsp.StatusCode = 404
rsp.Body = ` + "`" + `{"error":"not found"}` + "`" + `
return nil
}
rec := &responseRecorder{headers: make(map[string]string), statusCode: 200}
fakeReq, _ := http.NewRequestWithContext(ctx, req.Method, req.Path, nil)
handler(rec, fakeReq)
rsp.StatusCode = int32(rec.statusCode)
rsp.Body = rec.body
rsp.Headers = rec.headers
return nil
}
type responseRecorder struct {
headers map[string]string
body string
statusCode int
}
func (r *responseRecorder) Header() http.Header { return http.Header{} }
func (r *responseRecorder) WriteHeader(statusCode int) { r.statusCode = statusCode }
func (r *responseRecorder) Write(b []byte) (int, error) {
r.body = string(b)
return len(b), nil
}
`
)
+225
View File
@@ -0,0 +1,225 @@
package template
var (
CrudProtoSRV = `syntax = "proto3";
package {{dehyphen .Alias}};
option go_package = "./proto;{{dehyphen .Alias}}";
service {{title .Alias}} {
rpc Create(CreateRequest) returns (CreateResponse) {}
rpc Read(ReadRequest) returns (ReadResponse) {}
rpc Update(UpdateRequest) returns (UpdateResponse) {}
rpc Delete(DeleteRequest) returns (DeleteResponse) {}
rpc List(ListRequest) returns (ListResponse) {}
}
message {{title .Alias}}Record {
string id = 1;
string name = 2;
string email = 3;
string phone = 4;
string company = 5;
int64 created = 6;
int64 updated = 7;
}
message CreateRequest {
string name = 1;
string email = 2;
string phone = 3;
string company = 4;
}
message CreateResponse {
{{title .Alias}}Record record = 1;
}
message ReadRequest {
string id = 1;
}
message ReadResponse {
{{title .Alias}}Record record = 1;
}
message UpdateRequest {
string id = 1;
string name = 2;
string email = 3;
string phone = 4;
string company = 5;
}
message UpdateResponse {
{{title .Alias}}Record record = 1;
}
message DeleteRequest {
string id = 1;
}
message DeleteResponse {
bool deleted = 1;
}
message ListRequest {
int64 limit = 1;
int64 offset = 2;
}
message ListResponse {
repeated {{title .Alias}}Record records = 1;
int64 total = 2;
}
`
CrudHandlerSRV = `package handler
import (
"context"
"fmt"
"sort"
"sync"
"time"
"github.com/google/uuid"
log "go-micro.dev/v6/logger"
pb "{{.Dir}}/proto"
)
type {{title .Alias}} struct {
mu sync.RWMutex
records map[string]*pb.{{title .Alias}}Record
}
func New() *{{title .Alias}} {
return &{{title .Alias}}{
records: make(map[string]*pb.{{title .Alias}}Record),
}
}
// Create adds a new record and returns it with a generated ID.
//
// @example {"name": "Alice Smith", "email": "alice@example.com", "phone": "+1-555-0100", "company": "Acme Inc"}
func (h *{{title .Alias}}) Create(ctx context.Context, req *pb.CreateRequest, rsp *pb.CreateResponse) error {
log.Infof("Creating record: %s", req.Name)
now := time.Now().Unix()
record := &pb.{{title .Alias}}Record{
Id: uuid.New().String(),
Name: req.Name,
Email: req.Email,
Phone: req.Phone,
Company: req.Company,
Created: now,
Updated: now,
}
h.mu.Lock()
h.records[record.Id] = record
h.mu.Unlock()
rsp.Record = record
return nil
}
// Read retrieves a record by ID.
//
// @example {"id": "some-uuid"}
func (h *{{title .Alias}}) Read(ctx context.Context, req *pb.ReadRequest, rsp *pb.ReadResponse) error {
h.mu.RLock()
record, ok := h.records[req.Id]
h.mu.RUnlock()
if !ok {
return fmt.Errorf("record %s not found", req.Id)
}
rsp.Record = record
return nil
}
// Update modifies an existing record. Only non-empty fields are updated.
//
// @example {"id": "some-uuid", "name": "Alice Johnson", "email": "alice.j@example.com"}
func (h *{{title .Alias}}) Update(ctx context.Context, req *pb.UpdateRequest, rsp *pb.UpdateResponse) error {
h.mu.Lock()
defer h.mu.Unlock()
record, ok := h.records[req.Id]
if !ok {
return fmt.Errorf("record %s not found", req.Id)
}
if req.Name != "" {
record.Name = req.Name
}
if req.Email != "" {
record.Email = req.Email
}
if req.Phone != "" {
record.Phone = req.Phone
}
if req.Company != "" {
record.Company = req.Company
}
record.Updated = time.Now().Unix()
rsp.Record = record
return nil
}
// Delete removes a record by ID.
//
// @example {"id": "some-uuid"}
func (h *{{title .Alias}}) Delete(ctx context.Context, req *pb.DeleteRequest, rsp *pb.DeleteResponse) error {
h.mu.Lock()
_, ok := h.records[req.Id]
if ok {
delete(h.records, req.Id)
}
h.mu.Unlock()
rsp.Deleted = ok
return nil
}
// List returns all records with optional pagination.
//
// @example {"limit": 10, "offset": 0}
func (h *{{title .Alias}}) List(ctx context.Context, req *pb.ListRequest, rsp *pb.ListResponse) error {
h.mu.RLock()
defer h.mu.RUnlock()
all := make([]*pb.{{title .Alias}}Record, 0, len(h.records))
for _, r := range h.records {
all = append(all, r)
}
sort.Slice(all, func(i, j int) bool {
return all[i].Created > all[j].Created
})
rsp.Total = int64(len(all))
offset := int(req.Offset)
if offset > len(all) {
offset = len(all)
}
limit := int(req.Limit)
if limit <= 0 {
limit = 20
}
end := offset + limit
if end > len(all) {
end = len(all)
}
rsp.Records = all[offset:end]
return nil
}
`
)
+108
View File
@@ -0,0 +1,108 @@
package template
var (
HandlerSRV = `package handler
import (
"context"
log "go-micro.dev/v6/logger"
pb "{{.Dir}}/proto"
)
type {{title .Alias}} struct{}
// Return a new handler.
func New() *{{title .Alias}} {
return &{{title .Alias}}{}
}
// Call greets a person by name and returns a welcome message.
//
// @example {"name": "Alice"}
func (e *{{title .Alias}}) Call(ctx context.Context, req *pb.Request, rsp *pb.Response) error {
log.Info("Received {{title .Alias}}.Call request")
rsp.Msg = "Hello " + req.Name
return nil
}
// Stream sends a sequence of numbered responses back to the caller.
// Use this for streaming large result sets or real-time updates.
//
// @example {"count": 5}
func (e *{{title .Alias}}) Stream(ctx context.Context, req *pb.StreamingRequest, stream pb.{{title .Alias}}_StreamStream) error {
log.Infof("Received {{title .Alias}}.Stream request with count: %d", req.Count)
for i := 0; i < int(req.Count); i++ {
log.Infof("Responding: %d", i)
if err := stream.Send(&pb.StreamingResponse{
Count: int64(i),
}); err != nil {
return err
}
}
return nil
}
`
// HandlerNoProto is the default handler: plain Go request/response types
// registered by reflection. No generated protobuf code, so no protoc.
HandlerNoProto = `package handler
import (
"context"
log "go-micro.dev/v6/logger"
)
// Request is the input to {{title .Alias}}.Call.
type Request struct {
Name string ` + "`json:\"name\" description:\"Name to greet (required)\"`" + `
}
// Response is the output of {{title .Alias}}.Call.
type Response struct {
Msg string ` + "`json:\"msg\"`" + `
}
type {{title .Alias}} struct{}
// Return a new handler.
func New() *{{title .Alias}} {
return &{{title .Alias}}{}
}
// Call greets a person by name and returns a welcome message.
//
// @example {"name": "Alice"}
func (e *{{title .Alias}}) Call(ctx context.Context, req *Request, rsp *Response) error {
log.Info("Received {{title .Alias}}.Call request")
rsp.Msg = "Hello " + req.Name
return nil
}
`
SubscriberSRV = `package subscriber
import (
"context"
log "go-micro.dev/v6/logger"
pb "{{.Dir}}/proto"
)
type {{title .Alias}} struct{}
func (e *{{title .Alias}}) Handle(ctx context.Context, msg *pb.Message) error {
log.Info("Handler Received message: ", msg.Say)
return nil
}
func Handler(ctx context.Context, msg *pb.Message) error {
log.Info("Function Received message: ", msg.Say)
return nil
}
`
)
+8
View File
@@ -0,0 +1,8 @@
package template
var (
GitIgnore = `
{{.Alias}}
.micro
`
)
+111
View File
@@ -0,0 +1,111 @@
package template
var (
MainSRV = `package main
import (
"{{.Dir}}/handler"
pb "{{.Dir}}/proto"
"go-micro.dev/v6"
"go-micro.dev/v6/gateway/mcp"
)
func main() {
// Create service
service := micro.NewService("{{lower .Alias}}",
mcp.WithMCP(":3001"),
)
// Initialize service
service.Init()
// Register handler
pb.Register{{title .Alias}}Handler(service.Server(), handler.New())
// Run service
service.Run()
}
`
MainSRVNoMCP = `package main
import (
"{{.Dir}}/handler"
pb "{{.Dir}}/proto"
"go-micro.dev/v6"
)
func main() {
// Create service
service := micro.NewService("{{lower .Alias}}")
// Initialize service
service.Init()
// Register handler
pb.Register{{title .Alias}}Handler(service.Server(), handler.New())
// Run service
service.Run()
}
`
// MainNoProto is the default template: handlers are registered by
// reflection, so the service builds and runs with no protoc toolchain.
MainNoProto = `package main
import (
"{{.Dir}}/handler"
"go-micro.dev/v6"
"go-micro.dev/v6/gateway/mcp"
log "go-micro.dev/v6/logger"
)
func main() {
// Create service
service := micro.NewService("{{lower .Alias}}",
mcp.WithMCP(":3001"),
)
// Initialize service
service.Init()
// Register handler (reflection-based — no protoc required)
if err := service.Handle(handler.New()); err != nil {
log.Fatal(err)
}
// Run service
service.Run()
}
`
MainNoProtoNoMCP = `package main
import (
"{{.Dir}}/handler"
"go-micro.dev/v6"
log "go-micro.dev/v6/logger"
)
func main() {
// Create service
service := micro.NewService("{{lower .Alias}}")
// Initialize service
service.Init()
// Register handler (reflection-based — no protoc required)
if err := service.Handle(handler.New()); err != nil {
log.Fatal(err)
}
// Run service
service.Run()
}
`
)
+119
View File
@@ -0,0 +1,119 @@
package template
// MakefileNoProto is the default Makefile: no proto target, nothing to
// generate, so the service builds and runs with no protoc toolchain.
var MakefileNoProto = `.PHONY: build run dev test test-coverage clean docker lint fmt deps
# Build the service
build:
go build -o bin/{{.Alias}} .
# Run the service
run:
go run .
# Run with hot reload (requires air: go install github.com/air-verse/air@latest)
dev:
air
# Run tests
test:
go test -v ./...
# Run tests with coverage
test-coverage:
go test -v -coverprofile=coverage.out ./...
go tool cover -html=coverage.out -o coverage.html
# List MCP tools exposed by this service
mcp-tools:
micro mcp list
# Start MCP server for Claude Code
mcp-serve:
micro mcp serve
# Clean build artifacts
clean:
rm -rf bin/ coverage.out coverage.html
# Build Docker image
docker:
docker build -t {{.Alias}}:latest .
# Lint code
lint:
golangci-lint run ./...
# Format code
fmt:
go fmt ./...
goimports -w .
# Update dependencies
deps:
go mod tidy
go mod download
`
var Makefile = `.PHONY: proto build run test clean docker
# Generate protobuf files
proto:
protoc --proto_path=. --micro_out=. --go_out=. proto/*.proto
# Build the service
build:
go build -o bin/{{.Alias}} .
# Run the service
run:
go run .
# Run with hot reload (requires air: go install github.com/air-verse/air@latest)
dev:
air
# Run tests
test:
go test -v ./...
# Run tests with coverage
test-coverage:
go test -v -coverprofile=coverage.out ./...
go tool cover -html=coverage.out -o coverage.html
# List MCP tools exposed by this service
mcp-tools:
micro mcp list
# Test an MCP tool interactively
mcp-test:
micro mcp test
# Start MCP server for Claude Code
mcp-serve:
micro mcp serve
# Clean build artifacts
clean:
rm -rf bin/ coverage.out coverage.html
# Build Docker image
docker:
docker build -t {{.Alias}}:latest .
# Lint code
lint:
golangci-lint run ./...
# Format code
fmt:
go fmt ./...
goimports -w .
# Update dependencies
deps:
go mod tidy
go mod download
`
+28
View File
@@ -0,0 +1,28 @@
package template
var (
Module = `module {{.Dir}}
go 1.22
require (
go-micro.dev/v6 {{.MicroVersion}}
github.com/golang/protobuf latest
google.golang.org/protobuf latest
)
{{if .MicroReplace}}
replace go-micro.dev/v6 => {{.MicroReplace}}
{{end}}`
// ModuleNoProto is the default go.mod: no protobuf dependencies.
// MicroVersion is the version this CLI was built from (or "latest"), so a
// generated service tracks the framework the user is actually running.
ModuleNoProto = `module {{.Dir}}
go 1.23
require go-micro.dev/v6 {{.MicroVersion}}
{{if .MicroReplace}}
replace go-micro.dev/v6 => {{.MicroReplace}}
{{end}}`
)
+39
View File
@@ -0,0 +1,39 @@
package template
var (
ProtoSRV = `syntax = "proto3";
package {{dehyphen .Alias}};
option go_package = "./proto;{{dehyphen .Alias}}";
service {{title .Alias}} {
rpc Call(Request) returns (Response) {}
rpc Stream(StreamingRequest) returns (stream StreamingResponse) {}
}
message Message {
string say = 1;
}
message Request {
// Name of the person to greet
string name = 1;
}
message Response {
// Greeting message
string msg = 1;
}
message StreamingRequest {
// Number of responses to stream back
int64 count = 1;
}
message StreamingResponse {
// Current sequence number in the stream
int64 count = 1;
}
`
)
+184
View File
@@ -0,0 +1,184 @@
package template
var (
PubsubProtoSRV = `syntax = "proto3";
package {{dehyphen .Alias}};
option go_package = "./proto;{{dehyphen .Alias}}";
service {{title .Alias}} {
rpc Publish(PublishRequest) returns (PublishResponse) {}
rpc Stats(StatsRequest) returns (StatsResponse) {}
}
message Event {
string id = 1;
string type = 2;
string source = 3;
string data = 4;
int64 timestamp = 5;
}
message PublishRequest {
string type = 1;
string data = 2;
}
message PublishResponse {
string id = 1;
}
message StatsRequest {}
message StatsResponse {
int64 published = 1;
int64 received = 2;
}
`
PubsubHandlerSRV = `package handler
import (
"context"
"encoding/json"
"sync/atomic"
"time"
"github.com/google/uuid"
"go-micro.dev/v6/broker"
log "go-micro.dev/v6/logger"
pb "{{.Dir}}/proto"
)
const Topic = "{{lower .Alias}}.events"
type {{title .Alias}} struct {
broker broker.Broker
published atomic.Int64
received atomic.Int64
}
func New(b broker.Broker) *{{title .Alias}} {
return &{{title .Alias}}{broker: b}
}
// Publish sends an event to the message broker.
//
// @example {"type": "user.created", "data": "{\"id\": \"123\", \"name\": \"Alice\"}"}
func (h *{{title .Alias}}) Publish(ctx context.Context, req *pb.PublishRequest, rsp *pb.PublishResponse) error {
event := &pb.Event{
Id: uuid.New().String(),
Type: req.Type,
Source: "{{lower .Alias}}",
Data: req.Data,
Timestamp: time.Now().Unix(),
}
body, err := json.Marshal(event)
if err != nil {
return err
}
if err := h.broker.Publish(Topic, &broker.Message{Body: body}); err != nil {
return err
}
h.published.Add(1)
log.Infof("Published event %s type=%s", event.Id, event.Type)
rsp.Id = event.Id
return nil
}
// Stats returns the number of events published and received.
//
// @example {}
func (h *{{title .Alias}}) Stats(ctx context.Context, req *pb.StatsRequest, rsp *pb.StatsResponse) error {
rsp.Published = h.published.Load()
rsp.Received = h.received.Load()
return nil
}
// Subscribe sets up a subscription to the event topic. Call this
// after the service has started.
func (h *{{title .Alias}}) Subscribe() error {
_, err := h.broker.Subscribe(Topic, func(p broker.Event) error {
h.received.Add(1)
var event pb.Event
if err := json.Unmarshal(p.Message().Body, &event); err != nil {
log.Errorf("Failed to unmarshal event: %v", err)
return nil
}
log.Infof("Received event %s type=%s data=%s", event.Id, event.Type, event.Data)
return nil
})
return err
}
`
PubsubMainSRV = `package main
import (
"{{.Dir}}/handler"
pb "{{.Dir}}/proto"
"go-micro.dev/v6"
"go-micro.dev/v6/gateway/mcp"
log "go-micro.dev/v6/logger"
)
func main() {
service := micro.NewService("{{lower .Alias}}",
mcp.WithMCP(":3001"),
)
service.Init()
h := handler.New(service.Options().Broker)
pb.Register{{title .Alias}}Handler(service.Server(), h)
// Subscribe to events after service starts
go func() {
if err := h.Subscribe(); err != nil {
log.Fatalf("Failed to subscribe: %v", err)
}
log.Info("Subscribed to ", handler.Topic)
}()
service.Run()
}
`
PubsubMainSRVNoMCP = `package main
import (
"{{.Dir}}/handler"
pb "{{.Dir}}/proto"
"go-micro.dev/v6"
log "go-micro.dev/v6/logger"
)
func main() {
service := micro.NewService("{{lower .Alias}}")
service.Init()
h := handler.New(service.Options().Broker)
pb.Register{{title .Alias}}Handler(service.Server(), h)
go func() {
if err := h.Subscribe(); err != nil {
log.Fatalf("Failed to subscribe: %v", err)
}
log.Info("Subscribed to ", handler.Topic)
}()
service.Run()
}
`
)
+163
View File
@@ -0,0 +1,163 @@
package template
var (
// ReadmeNoProto is the default README: handlers are reflection-based, so
// there is no proto generation step and no protoc prerequisite.
ReadmeNoProto = `# {{title .Alias}} Service
Generated with
` + "```" + `
micro new {{.Alias}}
` + "```" + `
## Getting Started
Run the service — no code generation, no protoc, nothing else to install:
` + "```bash" + `
go run .
` + "```" + `
Handlers are registered by reflection from plain Go types, so request and
response structs are defined directly in ` + "`handler/`" + `. To use Protocol
Buffers instead, regenerate with ` + "`micro new {{.Alias}} --proto`" + `.
## MCP & AI Agents
This service is MCP-enabled by default. When running, AI agents can discover
and call your service endpoints automatically.
**MCP tools endpoint:** http://localhost:3001/mcp/tools
### Test with curl
` + "```bash" + `
# List available tools
curl http://localhost:3001/mcp/tools | jq
# Call the service via MCP
curl -X POST http://localhost:3001/mcp/call \
-H 'Content-Type: application/json' \
-d '{"tool": "{{lower .Alias}}.{{title .Alias}}.Call", "arguments": {"name": "Alice"}}'
` + "```" + `
### Use with Claude Code
` + "```bash" + `
# Start MCP server for Claude Code
micro mcp serve
` + "```" + `
### Writing Good Tool Descriptions
AI agents work best when your handler methods have clear doc comments:
` + "```go" + `
// CreateUser registers a new user account with the given email and name.
// Returns the created user with their assigned ID.
//
// @example {"email": "alice@example.com", "name": "Alice Smith"}
func (s *Users) CreateUser(ctx context.Context, req *CreateRequest, rsp *CreateResponse) error {
// ...
}
` + "```" + `
See the [tool descriptions guide](https://go-micro.dev/docs/guides/tool-descriptions) for more tips.
## Development
` + "```bash" + `
make build # Build binary
make test # Run tests
make dev # Run with hot reload (requires air)
` + "```" + `
`
Readme = `# {{title .Alias}} Service
Generated with
` + "```" + `
micro new {{.Alias}}
` + "```" + `
## Getting Started
Generate the proto code:
` + "```bash" + `
make proto
` + "```" + `
Run the service:
` + "```bash" + `
go run .
` + "```" + `
## MCP & AI Agents
This service is MCP-enabled by default. When running, AI agents can discover
and call your service endpoints automatically.
**MCP tools endpoint:** http://localhost:3001/mcp/tools
### Test with curl
` + "```bash" + `
# List available tools
curl http://localhost:3001/mcp/tools | jq
# Call the service via MCP
curl -X POST http://localhost:3001/mcp/call \
-H 'Content-Type: application/json' \
-d '{"tool": "{{lower .Alias}}.{{title .Alias}}.Call", "arguments": {"name": "Alice"}}'
` + "```" + `
### Use with Claude Code
` + "```bash" + `
# Start MCP server for Claude Code
micro mcp serve
` + "```" + `
Or add to your Claude Code config:
` + "```json" + `
{
"mcpServers": {
"{{lower .Alias}}": {
"command": "micro",
"args": ["mcp", "serve"]
}
}
}
` + "```" + `
### Writing Good Tool Descriptions
AI agents work best when your handler methods have clear doc comments:
` + "```go" + `
// CreateUser registers a new user account with the given email and name.
// Returns the created user with their assigned ID.
//
// @example {"email": "alice@example.com", "name": "Alice Smith"}
func (s *Users) CreateUser(ctx context.Context, req *CreateRequest, rsp *CreateResponse) error {
// ...
}
` + "```" + `
See the [tool descriptions guide](https://go-micro.dev/docs/guides/tool-descriptions) for more tips.
## Development
` + "```bash" + `
make proto # Regenerate proto code
make build # Build binary
make test # Run tests
make dev # Run with hot reload (requires air)
` + "```" + `
`
)