This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
KPow is a self-hosted, privacy-focused contact form server written in Go. It encrypts messages using Age, PGP, or RSA public keys before delivering them via SMTP email or webhook. No third-party services required.
just build # Build binary: go build -o kpow
just test # Run all tests: go test -v ./...
just check # Security scan: gosec ./...
just fmt # Format: gofmt -w .
just dev # Live reload with air
just styles # Build Tailwind CSS (requires bun)
just setup-tools # Install gosec, air, mockgenRun a single test:
go test -v ./server/enc -run TestEncryptAgeTests require TEST_KEYS_DIR (auto-set by Justfile to server/enc/testkeys). When running tests manually:
TEST_KEYS_DIR=$(pwd)/server/enc/testkeys go test -v ./...Generate mocks with mockgen (go.uber.org/mock).
Request flow: HTTP form POST → Echo handler → encrypt message → send via SMTP mailer and/or webhook → on failure, store in inbox → cron retries from inbox.
Key packages:
cmd/— Cobra CLI commands (start,verify). Thestartcommand loads config, applies CLI flag overrides, and boots the server.config/— TOML config parsing + env var overrides. Priority: TOML file → env vars → CLI flags (last wins).server/— Echo server setup, handler, error pages, embedded templates/static assets viaembed.FS.server/enc/— Encryption providers implementingenc.KeyLikeinterface (Age, PGP, RSA).server/mailer/—mailer.Mailerinterface with SMTP and webhook implementations. Webhook sends encrypted JSON payload.server/form/— Form binding and validation.server/cron/— Scheduled inbox retry for failed message delivery.
Interfaces: The codebase uses interface-based DI — enc.KeyLike for encryption, mailer.Mailer for delivery. The Handler struct composes these.
Config: Supports TOML file, environment variables, and CLI flags. Either mailer.dsn or webhook.url must be configured (webhook-only mode is supported).
Frontend: HTML templates + Tailwind CSS. Styles compiled with bunx @tailwindcss/cli. Static assets embedded in binary.
- Check
docs/for relevant ADRs and plans before exploring broadly. - When a plan file exists, read the ENTIRE plan before starting.
- Summarize your intended approach and wait for confirmation before implementing.
- Do NOT deviate from a plan's specified approach unless explicitly asked.
- Architecture: DDD + Clean Architecture. Manual DI, no frameworks. Business logic in application layer, not database.
- Philosophy: Pragmatic MVP — core functionality over complex features, essential security with practical implementation.
- Dependencies: Prefer well-maintained, widely-known libraries. Leverage existing solutions over building custom.
- Naming: Prefer longer but clear variable names (
workspaceoverws,titlebarovertb). - Comments: Simple docstrings only. No decorative separators (
//-----,//=====,/* ── ... ── */), no ASCII art. - Complex logic: Use mermaid diagrams over lengthy text. Add a README in the module if needed.
Use simple commits, should not start with capital case letter. No conventional commits. Simple short sentences.
- Prefer the simplest approach. Do not add complexity unless explicitly requested.
- Before implementing, grep the codebase for similar patterns and match them exactly.
- Use existing project interfaces and utilities. Do not reimplement what exists.
When modifying encryption or security code:
- Read relevant files in
server/enc/to understand theKeyLikeinterface and existing patterns. - Grep for all usages of the types/functions being changed.
- Present analysis: current patterns, proposed approach, conventions you'll follow.
- Wait for approval before implementing.
After changes verify: no keys logged/exposed in errors, sensitive data not leaked in error messages.
After changes, always run:
just test— all tests must passjust check— security scan with gosec