Files
prompts/prompts/CODE_STYLEGUIDE.md
sneak 00c21cc5c5 Fix heading, scope, version placement, and consistency across policy docs
- Rename REPO_POLICIES.md heading from "Development Policies" to
  "Repository Policies" to distinguish from code styleguides
- Move version line above heading per convention
- Add scope statement and links to code styleguide documents
- Add missing Makefile and LICENSE to minimum files list
- Add version lines to all cross-project docs (CODE_STYLEGUIDE*.md,
  GO_HTTP_SERVER_CONVENTIONS.md)
- Clean up CODE_STYLEGUIDE.md heading (was old repo name)
- Update EXISTING_REPO_CHECKLIST.md link text to match new heading
2026-02-22 16:40:34 +01:00

4.0 KiB

Version: 2026-02-22

Code Styleguide

All

  1. Every project/repo should have a Makefile in the root. At a minimum, make clean, make run, make fmt, and make test should work. Choose a sane default target (test for libraries, run or publish for binaries). fmt should invoke the appropriate formatters for the files in the repo, such as go fmt, prettier, black, etc. Other standard Makefile targets include deploy, lint. Consider the Makefile the official documentation about how to operate the repository.

  2. If it's possible to write a Dockerfile, include at least a simple one. It should be possible to build and run the project with docker build ..

  3. For F/OSS-licensed software, try to include the full source code of the current version (and any dependencies, such as vendored dependencies) in the docker image. They're small and should be included with the binary.

  4. Under no circumstances should any credentials or secrets ever be committed to any repository, even private ones. Store secrets in environment variables, and if they are absolutely required, check on startup to make sure they are set/non-default and complain loudly if not. Exception, sometimes: public keys. (Public keys can still sometimes be secrets for operational security reasons.)

  5. Avoid nesting if statements. If you have more than one level of nesting, consider inverting the condition and using return to exit early.

  6. Almost all services/servers should accept their configuration via environment variables. Only go full config file if absolutely necessary.

  7. For services/servers, log JSON to stdout. This makes it easier to parse and aggregate logs when run under docker. Use structured logging whenever possible. You may detect if the output is a terminal and pretty-print the logs in that case.

  8. Debug mode is enabled by setting the environment variable DEBUG to a non-empty string. This should enable verbose logging and such. It will never be enabled in prod.

  9. For services/servers, make a healthcheck available at /.well-known/healthcheck. This is out of spec but it is my personal standard. This should return a 200 OK if the service is healthy, along with a JSON object containing the service's name, uptime, and any other relevant information, and a key of "status" with a value of "ok" if the service is healthy. Make sure that in the event of a failure, the service returns a 5xx status code for that route.

  10. If possible, for services/servers, include a /metrics endpoint that returns Prometheus-formatted metrics. This is not required for all services, but is a nice-to-have.

Bash / Shell

  1. Use [[ instead of [ for conditionals. It's a shell builtin and doesn't have to execute a separate process.

  2. Use $( ) instead of backticks. It's easier to read and nest.

  3. Use #!/usr/bin/env bash as the shebang line. This allows the script to be run on systems where bash is not in /bin.

  4. Use set -euo pipefail at the top of every script. This will cause the script to exit if any command fails, and will cause the script to exit if any variable is used before it is set.

  5. Use pv for progress bars when piping data through a command. This makes it easier to see how much data has been processed.

  6. Put all code in functions, even a main function. Define all functions then call main at the bottom of the file.

Docker Containers (for services)

  1. Use runit with runsvinit as the entrypoint for all containers. This allows for easy service management and logging. In startup scripts (/etc/service/*/run) in the container, put a sleep 1 at the top of the script to avoid spiking the cpu in the case of a fast-exiting process (such as in an error condition). This also limits the maximum number of error messages in logs to 86400/day.

Author

@sneak <sneak@sneak.berlin>

License

MIT. See LICENSE.