Thank you for your interest in contributing to VoidLLM! This guide will help you get started.
- Go 1.23+
- Node.js 20+ (for UI development)
- Docker (optional, for Postgres/Redis)
git clone https://github.com/voidmind-io/voidllm
cd voidllm
# Copy and edit config
cp voidllm.yaml.example voidllm.yaml
# Generate required keys
export VOIDLLM_ADMIN_KEY=$(openssl rand -base64 32)
export VOIDLLM_ENCRYPTION_KEY=$(openssl rand -base64 32)
# Run
go run ./cmd/voidllm --config voidllm.yaml
# Run tests
go test -race ./...go install github.com/air-verse/air@latest
air- Fork the repository
- Create a branch from
main:git checkout -b feat/my-feature - Write code — follow the conventions below
- Write tests — table-driven, parallel, real SQLite (no mocks)
- Run checks:
go test -race ./... && go vet ./... - Commit with a descriptive message (see Commit Messages below)
- Open a Pull Request against
main
- No
// TODOcomments — if it's not implemented, it's not in the code - No stubs or placeholder functions — every function does what its signature promises
- No
panic()— return errors - No
fmt.Println— useslogfor logging - No
any/interface{}without explicit justification - Every exported symbol has a godoc comment
- Every error path is handled — no
_ = someFunc()on fallible operations - Error strings: lowercase, no trailing punctuation
- Error wrapping:
fmt.Errorf("operation context: %w", err) - Context:
context.Contextis always the first parameter - Tests: table-driven with
t.Parallel(), real SQLite in-memory DB (no mocks for storage)
- Parameterized queries only — never concatenate user input into SQL
- Use
dialect.Placeholder(n)for cross-database compatibility defer rows.Close()after everyQueryContext- Check
rows.Err()after every scan loop
- API keys: HMAC-SHA256 hashed, never stored in plaintext
- Upstream API keys: AES-256-GCM encrypted in the database
- Headers: allowlist approach (not blocklist) for forwarding
- Secrets: never in logs — use
slog.LogValuerfor redaction - Privacy: no prompt or response content is ever stored or logged
Follow Conventional Commits:
feat: add team membership CRUD
fix: close cross-org IDOR in membership deletion
refactor: extract requireOrgAccess helper
docs: add deployment constraints to README
test: add concurrent CAS correctness test for rate limiter
cmd/voidllm/ — Binary entrypoint (wiring only, no business logic)
internal/
config/ — YAML config loading, validation
logger/ — Structured logging setup
db/ — Database layer (SQLite, migrations, CRUD)
cache/ — Generic in-memory cache (sync.Map)
auth/ — Auth middleware, RBAC, bootstrap, key cache loader
proxy/ — LLM proxy handler, model registry, provider adapters
usage/ — Async usage event logger
ratelimit/ — Rate limiting + token budget enforcement
api/
admin/ — Admin API handlers (CRUD for all entities)
health/ — Health, readiness, and metrics endpoints
pkg/
crypto/ — AES-256-GCM encryption utilities
keygen/ — API key generation + HMAC hashing
enterprise/ — Proprietary (see enterprise/LICENSE.md)
ui/ — Frontend SPA (coming in v0.2)
- Load balancing / fallback between providers (premium feature)
- Per-model rate limits (premium feature)
- Prompt caching or storage
- Any code that stores or logs prompt/response content
Open an issue on GitHub.