Skip to main content
This guide covers commit message format, code style, and the PR submission process.

Commit Message Format

All commits must follow Conventional Commits format:
<type>[optional scope]: <description>

[optional body]

[optional footer(s)]

Commit Types

  • feat: New feature
  • fix: Bug fix
  • docs: Documentation changes
  • style: Code style changes (formatting, no logic changes)
  • refactor: Code refactoring (no behavior changes)
  • perf: Performance improvements
  • test: Adding or updating tests
  • build: Build system or dependency changes
  • ci: CI/CD configuration changes
  • chore: Maintenance tasks
  • revert: Revert a previous commit

Examples

feat(policy): add support for CEL expressions in bot matching

fix: resolve event loop thrashing in proof-of-work solver

docs: update installation guide for Go 1.24

refactor(store)!: change Store interface to return errors

BREAKING CHANGE: Store.Get now returns ([]byte, error) instead of []byte

Commit Rules

  • Keep descriptions concise
  • Use imperative mood (“add feature” not “added feature”)
  • Use lowercase for descriptions
  • No trailing period
  • Add ! after type/scope for breaking changes
  • Use BREAKING CHANGE: in footer for breaking changes
  • Reference issues/PRs in footer when applicable

Signed Commits (REQUIRED)

ALL commits MUST be signed with --signoff. This is mandatory and enforced by commitlint.

Sign Your Commits

Every commit must include a Signed-off-by line:
git commit --signoff -m "feat: add new feature"
Or use the -s shorthand:
git commit -s -m "fix: resolve race condition"

AI Agent Attribution

If you’re using an AI coding tool, you must disclose it in the commit footer:
feat: implement rate limiting for challenge requests

Assisted-by: Claude 4.5 Sonnet via OpenCode
Signed-off-by: Your Name <[email protected]>
Format:
Assisted-by: [Model Name] via [Tool Name]

Automatic Signoff

Configure Git to sign off commits automatically:
git config --local commit.gpgsign true
Or use a Git hook (see .husky/commit-msg in the repository).

Code Style

Go

Anubis follows Go standard library idioms:
  • Formatting: Use goimports (run npm run format)
  • Package aliases: Only when names collide
  • Naming:
    • PublicFunctionsAndTypes in PascalCase
    • privateFunctionsAndTypes in camelCase
    • Acronyms stay uppercase (URL, HTTP, IP, DNS)
  • Errors:
    • Sentinel errors as package-level Err prefixed variables
    • Wrap with fmt.Errorf("package: context: %w", err)
    • Use errors.Is for validation
  • Logging:
    • Use log/slog for structured logging
    • Pass loggers as function arguments
    • Prefer slog.Debug unless users need to see the message
  • Configuration:
    • Use both json and yaml struct tags
    • Use pointer values for optional fields
    • Validate with Valid() error methods
  • Tests:
    • Use table-driven tests
    • Use t.Helper() in helper functions
    • Use t.Cleanup() for teardown
    • Prefer same-package tests over _test packages

JavaScript/TypeScript

  • Source in web/js/
  • Built with esbuild
  • Uses Preact (not React)
  • Use const by default
  • Keep functions small
  • No linter config - rely on code review

Templ Templates

  • .templ files in web/ generate Go code
  • Run npm run assets after modifying
  • Keep logic in Go, not templates
  • Templates receive typed Go parameters

Pull Request Process

Before Submitting

  1. Build assets:
    npm run assets
    
  2. Run tests:
    npm run test
    npm run test:integration
    
  3. Run linting:
    npm run lint
    
  4. Format code:
    npm run format
    
  5. Update CHANGELOG: Add your changes to [Unreleased] in docs/docs/CHANGELOG.md

PR Checklist

  • All commits follow Conventional Commits format
  • All commits are signed with --signoff
  • All commits have verified (signed) signatures
  • Tests added for bug fixes and new features
  • Integration tests pass (npm run test:integration)
  • CHANGELOG updated in docs/docs/CHANGELOG.md
  • AI tool attribution added if applicable
  • Code follows project style guidelines

Creating the PR

  1. Push your branch:
    git push origin feature/my-feature
    
  2. Open PR on GitHub
  3. Fill out template (see .github/PULL_REQUEST_TEMPLATE.md)
  4. Request review

PR Review

Anubis is security software - code reviews are strict:
  • Security implications are carefully evaluated
  • Test coverage is required
  • Adversarial inputs are considered
  • Breaking changes require discussion

Security Considerations

Anubis is security software. All contributions must consider adversarial scenarios.

Security-First Principles

  • Input validation: Validate all external input
  • Error handling: Don’t leak internal state in error messages
  • Rate limiting: Consider DoS scenarios
  • Cryptography: Use standard library crypto packages
  • Dependencies: Minimize external dependencies

Reporting Security Issues

See SECURITY.md for the security policy and reporting process.

Key Conventions

Configuration

  • YAML-based policy files
  • Config structs validate via Valid() error returning sentinel errors
  • See lib/config/ for examples

Store Interface

  • lib/store.Interface abstracts key-value storage
  • Implementations in lib/store/
  • Always handle errors from Store operations

Environment Variables

  • Parsed from flags via flagenv
  • Use .env files locally (loaded by godotenv/autoload)
  • NEVER commit .env files

Asset Building

  • JS/CSS assets embed into Go binary
  • Always run npm run assets before go test or go build
  • Generated files are committed to the repo

CEL Expressions

  • Policy rules support Common Expression Language
  • See lib/policy/expressions/ for implementation
  • Use for advanced bot matching rules

Project Layout

Key directories:
  • cmd/anubis/ - Main entrypoint
  • lib/*/ - Public library code (no API stability guarantees)
  • internal/*/ - Private implementation code
  • test/*/ - Smoke tests
  • web/ - Frontend templates
  • xess/ - CSS framework

Getting Help

Build docs developers (and LLMs) love