AgentSkillsCN

make-service

在 Accelerator 项目中新增 Go 服务的指南。

SKILL.md
--- frontmatter
name: make-service
description: Guide for adding a new Go service to the Accelerator project.

If you are making a plan, save it in the temp-plans/ folder. If not making a plan, implement directly.

Adding a New Service

Quick Start

bash
mkdir {servicename}
cd {servicename}
go mod init {servicename}

⚠️ IMPORTANT: Add {servicename}/{servicename} to .gitignore immediately (the built binary should never be committed)

Non-Obvious Decisions

1. Dockerfiles build from project root

Because services import shared api/generated/ code:

dockerfile
# {servicename}/Dockerfile
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
COPY api/ api/
COPY {servicename}/ {servicename}/
WORKDIR /app/{servicename}
RUN go mod download && CGO_ENABLED=0 go build -o /bin/{servicename} .

FROM alpine:latest
COPY --from=builder /bin/{servicename} /bin/{servicename}
CMD ["/bin/{servicename}"]

2. go.mod needs replace directive

go
require accelerator v0.0.0
replace accelerator => ../

And add to go.work:

go
use ./{servicename}

3. docker-compose uses Taskfile vars

yaml
{servicename}:
  build:
    context: .                           # Project root, not service folder
    dockerfile: {servicename}/Dockerfile
  environment:
    SAMPLE_RATE: ${SAMPLE_RATE}          # From Taskfile vars
    CHANNELS: ${CHANNELS}
    NATS_URL: nats://nats:4222           # Docker-specific, hardcoded

4. Use generated types, not manual ones

go
import accelerator "accelerator/api/generated"

// Channel paths from generated constants
accelerator.AudiorecorderAudioRawChannelPath

// Controllers handle pub/sub
ctrl, _ := accelerator.NewAppController(broker)
ctrl.SubscribeTo{Operation}(ctx, handler)
ctrl.SendAs{Operation}(ctx, msg)

5. Config has no subjects

Subjects come from generated constants. Config only has:

  • NATSUrl (with localhost default for native dev)
  • Service-specific settings

Native vs Docker Services

Ask: "Does this service need native OS access?"

AnswerAction
No (only NATS pub/sub)Add to docker-compose.yml, include in task up
Yes (mic, keyboard, etc.)Create standalone task {servicename} to run natively

Examples:

  • bindingregistry → Docker (only reads/writes NATS)
  • keylogger → Native (needs macOS CGEventTap for keyboard capture)
  • audiorecorder → Native (needs mic access)

Unit Tests

1. Create test files

Add tests in {servicename}/*_test.go. Mock external dependencies (NATS, keylogger events, etc.) by passing simulated data directly to functions.

2. Create test Dockerfile

Dockerfiles/{servicename}.test.Dockerfile:

dockerfile
FROM golang:1.22-alpine
WORKDIR /app

# Copy root module with generated code
COPY go.mod go.sum ./
COPY api/ api/

# Copy service module
COPY {servicename}/go.mod {servicename}/go.sum ./{servicename}/
WORKDIR /app/{servicename}
RUN go mod download

# Copy service source
WORKDIR /app
COPY {servicename}/ {servicename}/

WORKDIR /app/{servicename}
CMD ["go", "test", "-v", "./..."]

3. Add to docker-compose.test.yml

yaml
test-{servicename}:
  build:
    context: .
    dockerfile: Dockerfiles/{servicename}.test.Dockerfile

4. Add to Taskfile.yml

In the test:docker task, add a run command (with other Go tests):

yaml
- SAMPLE_RATE={{.SAMPLE_RATE}} CHANNELS={{.CHANNELS}} SAVE_INTERVAL_SEC={{.SAVE_INTERVAL_SEC}} docker compose -f docker-compose.test.yml run --rm test-{servicename}

After Adding Service

  1. ⚠️ CRITICAL: Add {servicename}/{servicename} to .gitignore - The compiled Go binary must be gitignored before any commits
  2. Update api/asyncapi.yaml with channels/messages
  3. Run task generate
  4. Add Dockerfile to Dockerfiles/{servicename}.Dockerfile
  5. Add to docker-compose.yml OR create task {servicename} (see above)
    • If Docker service: Also add to task up command in Taskfile.yml
  6. Add unit tests and wire into task test:docker (see Unit Tests section above)
  7. Update .env.example if the service requires API keys or secrets (e.g., GOOGLE_API_KEY, ANTHROPIC_API_KEY)
  8. Update PIPELINE.md - Add the service to:
    • Routing Table (Input/Output env vars)
    • Current Connections table (NATS subjects and payload types)
    • Payload Types section (document any new CloudEvent schemas)
    • ASCII Data Flow diagram - Add the new service to the visual pipeline diagram

Naming

WhatPatternExample
NATS subject{component}.{entity}.{action}transcriber.transcript.ready
CloudEvents typecom.accelerator.{component}.{event}com.accelerator.transcriber.transcriptReady