Contributing
How to contribute — development workflow, implementing Redis commands, and PR expectations.
Thanks for your interest in contributing.
The rest of this site is written for operators and users (install, configure, command surface, benchmarks). This page is the contributor entry point — development workflow, command implementation, and PR expectations.
Reporting issues
Search existing issues before opening a new one. Include:
- What you expected vs what happened
- Gateway / Redis client versions and OS
- Minimal reproduction (RESP bytes or
redis-clicommands)
Code contributions
- Fork and create a feature branch
- Keep changes focused; match existing Rust style
- Add or update tests under
pg_redis_gw//compat/as appropriate - For new Redis commands, follow Implementing a Redis command
Git history
Prefer rebase over merge commits when integrating work onto main (or
updating a feature branch):
- Rebase feature branches onto latest
mainbefore opening or updating a PR (git fetch origin && git rebase origin/main). - Land PRs with a rebase / squash-merge style so
mainstays a linear history — avoid creating merge commits onmainwhen a rebase will do. - When integrating parallel worktrees or sibling feature branches, rebase them
onto
main(or onto each other in order) rather thangit mergeing with a merge commit.
Resolve conflicts during the rebase; force-push to a feature branch only when you own that branch and reviewers are fine with a rewritten history.
Development
Preferred local runtime is the in-process gateway:
mise install
make postgres-up # embedded RESP gateway (preferred)
make postgres-restart # down + up (rebuild; keeps data volume)
make test
make compat # Valkey TCL against :6379 (embedded)
make bench # redis-benchmark vs Valkey baseline
make run # optional standalone gateway
The same targets are available via mise if you prefer (mise run postgres-up,
…). make run starts the optional standalone gateway against the same
Postgres. End-user run instructions live in Getting Started.
Implementing a Redis command
Ship semantics in SQL (pgresp.*), protocol binding in the gateway. Both the
in-process BGWorker and the standalone binary share redis_gateway_core — fix
behavior there once.
Semantics checklist
- Match Redis/Valkey arity and error text closely (
ERR wrong number of arguments for '…' command). - Command names are case-insensitive; keys/values are binary-safe (
bytea/ bulk strings). - Missing keys: Redis null bulk (
$-1\r\n) where Redis returns null (e.g.GET). - Empty string values are valid (not null). Cover them explicitly.
- Reject unsupported options explicitly rather than silently ignoring them.
- Prefer
pgresp.*functions/tables for behavior; keep the gateway free of business rules beyond param binding and RESP encoding.
Protocol surfaces (easy to miss)
Do not stop at redis-cli + allowlisted Valkey TCL. Those speak RESP arrays
and miss inline / telnet-style clients (e.g. redis-benchmark PING_INLINE).
When adding a simple command that benchmarks might send inline, add at least
one raw-bytes test for the inline form. Inline PING (PING\r\n) is supported.
Test surfaces
| Check | Target | Covers | Does not cover |
|---|---|---|---|
cargo test in pg_redis_gw |
Core + standalone | Unit decode/dispatch; some TCP tests | Full Valkey suite; durability matrix |
make postgres-up + make test |
Embedded gateway + Postgres | Live SET/GET against in-process RESP | Inline-only clients unless tests send raw bytes |
make compat |
Embedded :6379 via Valkey --host/--port |
Allowlisted TCL cases (RESP client) | Spawning valkey-server; inline wire form |
make bench |
Embedded :6379 vs Valkey :6380 |
Throughput; default ping,set,get |
Full semantic correctness |
Manual redis-cli |
Either runtime | Smoke / exploration | Automated CI signal |
Suggested workflow
- Implement
pgresp.*SQL (migration / extension) and session helpers. - Wire dispatch in
redis_gateway_corewith arity + reply encoding. - Unit-test decode/dispatch (wrong arity, empty value, happy path).
- Integration-test against a live gateway where Postgres is required.
- Enable matching Valkey test names in
compat/allowlist.txt; runmake compat. Put intentional non-goals incompat/out_of_scope.txt(Compatibility page shows them as out of scope, not failures). - Run
make compat-docsto refresh the Compatibility page. - If the command appears in default benchmarks, run
make benchor a focusedredis-benchmarkand confirm inline and mbulk forms if applicable. - Update
compat/STATUS.mdand the operator docs command matrix (docs/commands.mdx) / README surface notes.
PR expectations
- Green
make test(with Postgres up when integration tests need it). - Green
make compatfor any newly allowlisted names. - Rebase onto latest
mainbefore merge; prefer a linear history (see Git history). - Note any intentional Redis incompatibilities (unsupported options, singledb).
- Do not treat “compat passed” as proof that inline protocol or benchmark defaults work — call out which surfaces you exercised.
Docs site
This is a Blume site:
| Route | Source |
|---|---|
/ |
Marketing landing — pages/index.astro |
/docs/* |
Operator docs — docs/ MDX (basePath: "/docs" in blume.config.ts) |
Write MDX links as if mounted at the docs root (/getting-started); Blume
rewrites them under /docs. Config in blume.config.ts. Node and bun are
mise-managed:
mise install
bun install
bun run docs:dev # hot-reload preview
bun run docs:build # static site → dist/
Or via Make: make docs-dev / make docs-build.
Operator-facing pages should stay free of repo layout dumps and deep source
links. Put implementer detail here (or in CONTRIBUTING.md / compat/STATUS.md).
When command support or published benches change, update
Commands, Compatibility (make compat-docs), and
Benchmarks. App smoke-test results go on
Verified apps.
AI-assisted contributions
If AI tools were used substantially, say so in the PR description (tool + how). You remain responsible for understanding and testing every change.