Project challenges / verified progress
Beacon: turn a program into a service

The engineering notebook

Build one service binary

How do all the pieces become one artifact an operator can run?

Loading statusStage 10 of 10

  • Workspace not ready
  • Agent not ready
Focus25:00
A small focus ritual

0 focus sessions completed. Every fourth session offers a longer break. Start each phase when you are ready.

Study time never unlocks verified lesson progress.

Loading...

Loading verified progress...

Loading GitHub account...
Phase 4 — Process behaviour

Step 01 of 06

Learn the concept

A service is not finished when the packages work. Someone needs one binary, one help screen, one version string and one place where configuration is resolved. The final shape should be boring enough to run at 03:00.

SOURCE TO RUNNING SERVICE01Configresolved once02Wiremain connects deps03Buildone binary04Versioncommit visible05ServeAPI and checks
The binary is the delivery unit. Everything built in the course now has a place: config loads first, dependencies are wired once, the scheduler starts, HTTP serves, and version identity is visible.
Step 01

The ideas this is made of

Build flags shape the artifact

go build -o bin/beacond ./cmd/beacond writes a named binary instead of a temporary run. Operators and scripts can refer to bin/beacond consistently. Build flags should not hide required runtime settings; they create the artifact, not the environment it runs in.

ldflags stamp identity

-ldflags "-X main.version=1.2.3" sets a string variable at link time. Stamping version, commit and build time lets a running service answer what code it is. During incidents, I think this pod has the fix is not a diagnostic method.

A version endpoint is operational evidence

GET /version should return the service name, version, commit and build time. It must not expose secrets or local paths. The endpoint lets load balancers, humans and future automation confirm exactly which artifact is serving traffic.

Thin main keeps ownership clear

main parses config, creates loggers, opens stores, builds handlers, starts the scheduler and handles shutdown. It should not contain SQL, probing logic or JSON contract mapping. Thin main is not less important; it is where the service becomes a process.

Stamp a variable
package main

import "fmt"

var version = "dev"

func main() { fmt.Println(version) }

Build this with go build -ldflags "-X main.version=1.0.0" and the printed value changes without editing source. Beacon uses the same mechanism for /version.

Run versus build

CommandPurposeOutput

go run

Development

Temporary binary

go build

Artifact

Reusable file

go install

User tool

GOBIN path

ldflags -X

Stamp metadata

String variables

What these are called on the job

  • Artifact — The built file delivered and run, such as bin/beacond.

  • ldflags — Linker flags passed by go build, often used to set string variables.

  • Version stamping — Embedding release identity into the binary at build time.