Extend Commands API
redis/jedis
Add or extend Redis commands in the Jedis client API — a new core command, a family of new commands, an extension to an existing command's options, or a module command (Search/TimeSeries/JSON/Bloom).
Add or extend Redis commands in the Lettuce client API end-to-end — a new core command, a family of new commands, an extension to an existing command's options, or a module/area command…
$ npx skills add redis/lettuce --skill extend-commands-api -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install redis/lettuce extend-commands-api --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/redis/lettuce.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/extend-commands-api .claude/skills/extend-commands-api && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "extend-commands-api" agent skill from https://github.com/redis/lettuce/tree/main/.agents/skills/extend-commands-api into .claude/skills/extend-commands-api/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "extend-commands-api", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/redis/lettuce/tree/main/.agents/skills/extend-commands-apiType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add redis/lettuce --skill extend-commands-api -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install redis/lettuce extend-commands-api --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/redis/lettuce.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.agents/skills/extend-commands-api .agents/skills/extend-commands-api && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "extend-commands-api" agent skill from https://github.com/redis/lettuce/tree/main/.agents/skills/extend-commands-api into .agents/skills/extend-commands-api/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "extend-commands-api", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add redis/lettuce --skill extend-commands-api -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install redis/lettuce extend-commands-api --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/redis/lettuce.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.agents/skills/extend-commands-api .cursor/skills/extend-commands-api && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "extend-commands-api" agent skill from https://github.com/redis/lettuce/tree/main/.agents/skills/extend-commands-api into .cursor/skills/extend-commands-api/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "extend-commands-api", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/redis/lettuce.git --path .agents/skills/extend-commands-api--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add redis/lettuce --skill extend-commands-api -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install redis/lettuce extend-commands-api --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/redis/lettuce.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.agents/skills/extend-commands-api .gemini/skills/extend-commands-api && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "extend-commands-api" agent skill from https://github.com/redis/lettuce/tree/main/.agents/skills/extend-commands-api into .gemini/skills/extend-commands-api/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "extend-commands-api", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install redis/lettuce extend-commands-apiInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add redis/lettuce --skill extend-commands-api -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/redis/lettuce.git skills-src && mkdir -p .github/skills && cp -r skills-src/.agents/skills/extend-commands-api .github/skills/extend-commands-api && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "extend-commands-api" agent skill from https://github.com/redis/lettuce/tree/main/.agents/skills/extend-commands-api into .github/skills/extend-commands-api/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "extend-commands-api", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add redis/lettuce --skill extend-commands-api -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install redis/lettuce extend-commands-api --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/redis/lettuce.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.agents/skills/extend-commands-api .opencode/skills/extend-commands-api && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "extend-commands-api" agent skill from https://github.com/redis/lettuce/tree/main/.agents/skills/extend-commands-api into .opencode/skills/extend-commands-api/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "extend-commands-api", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
extend-commands-apiAdd or extend Redis commands in the Lettuce client API end-to-end — a new core command, a family of new commands, an extension to an existing command's options, or a module/area command…
Extend Commands API is an agent skill from redis/lettuce, published by the product's own GitHub organization. Add or extend Redis commands in the Lettuce client API end-to-end — a new core command, a family of new commands, an extension to an existing command's options, or a module/area command (Search/JSON/Bloom/VectorSet). Gathers evidence first (HLD document, the server-side PR in the repo owning the command family, live verification against the Dockerized test environment with redis-cli), plans the full implementation matrix in plan mode, then implements across all API flavors with unit and integration tests. Trigger…
Its SKILL.md is about 7.7k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Databases, covering Backend development, Planning and Integration testing. It works with Redis, Java, Amazon Web Services and Microsoft Azure. The licence is MIT.
2 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 114a3ef. It shows what the files ask for, not the result of running them.
Pre-approves these tools, so the agent can use them without asking each time:
Bash(mvn *)Bash(make *)Bash(redis-cli *)Bash(gh *)From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
mvnmakeghredis-cliFrom the folder's file list and the shell code blocks in SKILL.md.
Links to these hosts (documentation or services it may open):
hub.docker.comFrom URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Extend Commands API loads about 7.7k tokens when it runs. Until then it costs about 177 tokens; SKILL.md has 3,287 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check noted patterns worth knowing about, such as sudo or a known installer.
`src/test/resources/docker-env/.env.vX.XX` files — pick numerically, `8.10` >pinned in the `.env.vX.XX` file is too old. Ask the user for aove CI to that build, update the newest `.env.vX.XX`(cf. the hotkeys PR bumping `.env.v8.6`). If no tag carries the feature, reportditions, full integration overload set, `.env` image bump |- [ ] `.env.vX.XX` image pin bumped if the feature needed a newer server build.Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from redis/lettuce at commit 114a3ef, republished under its MIT licence (© redis). 3,287 words, ~7,726 tokens.
.claude/skills/extend-commands-api/SKILL.md (or your agent's skills folder).Implement a new Redis command (or extend an existing one) in Lettuce, following the conventions maintainers enforce in review. The workflow is evidence-first: prove the command's behavior on a real server before designing the Java API.
Read .agents/docs/architecture.md first for the model behind this flow — especially that the sync/async/reactive/Kotlin command interfaces are hand-edited source files kept in lockstep by the API consistency test suite (see .agents/docs/api-consistency.md).
Historical caveat when reading old PRs: PRs merged before the generator removal also edit
src/test/java/io/lettuce/core/api/<Group>Commands.java— the old template source files. Those files no longer exist; do not recreate them. The flavor interfaces are now edited directly.
Do all of the following before writing any plan or code:
Ask the user for the HLD. Interactively ask for the path to a markdown file containing the High-Level Design for the command(s) (or confirm none exists). If a path is given, read it fully — it is the primary source for syntax, semantics, reply shape per RESP2/RESP3, and edge cases.
Find the server-side PR in the repo that owns the command. Route the
search by command family — module command families are developed in their
owning repositories, not in redis/redis:
| Command family | Repository | Syntax source |
|---|---|---|
Core commands, vector sets (VADD, …) | redis/redis | src/commands/*.json |
Search (FT.*) | RediSearch/RediSearch | PR diff + command docs (no src/commands/*.json) |
JSON (JSON.*) | RedisJSON/RedisJSON | PR diff + command docs |
Probabilistic (BF.*, CF.*, CMS.*, TOPK.*, TDIGEST.*) | RedisBloom/RedisBloom | PR diff + command docs |
Time series (TS.*) | RedisTimeSeries/RedisTimeSeries | PR diff + command docs |
If the search comes up empty in the routed repo, fall back to redis/redis
(and vice versa) before concluding there is no server PR.
First verify that gh works in the current (sandboxed) environment:
gh auth statusSandboxes often block access to credential files, so gh may report
unauthenticated here even though it works on the user's machine. If so, ask the
user for permission to run these specific read-only gh commands outside the
sandbox; only fall back to the unauthenticated GitHub REST API if they decline.
Then search for the PR that adds/extends the command on the server:
gh search prs --repo <owning-repo> "<COMMAND NAME>" --limit 10
gh pr view <num> --repo <owning-repo>
gh pr diff <num> --repo <owning-repo> # in redis/redis: src/commands/*.json has exact syntaxExtract: exact wire syntax (argument order and optionality), reply type per
RESP2 and RESP3 (they can differ — this determines the CommandOutput and
the reactive Mono/Flux mapping), error conditions, and the first server
version carrying the feature (drives @EnabledOnCommand gating and the test
env version). Note whether the server marks the feature experimental/preview.
Verify the command exists on the "next" Redis OSS version. Start the
integration environment using the highest version the Makefile supports
(check SUPPORTED_TEST_ENV_VERSIONS in the Makefile, or the
src/test/resources/docker-env/.env.vX.XX files — pick numerically, 8.10 >
8.8):
grep SUPPORTED_TEST_ENV_VERSIONS Makefile
make start version=8.10Then probe the running servers. Test connection defaults live in
src/test/java/io/lettuce/test/settings/TestSettings.java — the main standalone
node is localhost:6479 (no auth); module commands (FT.*, JSON.*, BF.*,
VADD, …) run on the stack node at localhost:16379:
redis-cli -p 6479 INFO server | grep redis_version
redis-cli -p 6479 COMMAND INFO <COMMAND> # non-empty → command exists
redis-cli -p 6479 COMMAND DOCS <COMMAND> # arity/args — compare with the server PRFor a NEW command, COMMAND INFO must return a non-empty reply. For an EXTENDED
command, additionally invoke it with the new syntax against a scratch key and
confirm the server accepts it (no ERR syntax error / ERR unknown argument).
If the command/option is missing on the latest env version, the image tag
pinned in the .env.vX.XX file is too old. Ask the user for a
redislabs/client-libs-test image tag that contains it (e.g. an RC/edge build —
tags are listed at https://hub.docker.com/r/redislabs/client-libs-test/tags; you
may check and suggest candidates), then:
make stop
CLIENT_LIBS_TEST_IMAGE_TAG=<tag> make startIf the PR should also move CI to that build, update the newest .env.vX.XX
pin as part of the change — command PRs do this when they need a fresh server
(cf. the hotkeys PR bumping .env.v8.6). If no tag carries the feature, report
it and proceed: implementation continues, integration tests stay gated until an
image ships the change. Keep the environment running for later test runs.
Create redis-cli showcase test cases. Once the command is available, derive a small set of redis-cli scenarios from the HLD and the server PR and run them. These serve two purposes:
redis-cli -3 too when RESP3 replies
differ), edge cases and error conditions (missing key, out-of-range args,
conflicting options) — so the Java implementation is built against observed
replies, not assumptions.foo/bar.Save the scenarios as a commented script in a scratch file (one block per use-case: a "what this demonstrates" comment, the commands, the observed reply pasted back as comments). Carry this forward: it feeds the Phase 1 plan, the test assertions, and the PR description. If the command could not be made available on any image, still write the scenarios as expected transcripts and mark them unverified.
Read the testing and consistency docs:
.agents/docs/integration-testing.md
(environment, *UnitTests vs *IntegrationTests naming, base/overload test
structure, running one test) and
.agents/docs/api-consistency.md (the
flavors and their return-type mapping rules).
Trace one analogous existing command end-to-end (same command group, similar reply shape) so the plan mirrors real code, not guesswork. Good reference PRs, validated against git history:
| Commit | What it exemplifies |
|---|---|
7ca3e9cc0 (CLIENT NO-TOUCH #3776) | Minimal new command: all 6 flavors + builder + 2 dispatch layers + Kotlin impl + builder unit test + integration test |
312ecc7b4 (INCREX #3746) | New command with args: self-typed abstract args base, new value type, new CommandOutputs, per-type args/output unit tests, creating a missing RESP2 overload class |
b009df37b (XNACK #3728) | New command with an enum-valued argument |
9a0899875 (BITOP extensions #3334) | New operations/overloads on an existing command |
c603c8120 (HSCAN NOVALUES #2816) | New overload rippling into helpers (ScanIterator, ScanStream, ScanFlow) |
aa7b4b0be (stream idempotency #3637) | Option added to an existing *Args class flows through with no interface change (the XAddArgs part) |
a209fba70 (CAS/CAD #3512) | Read-only command registered in ReadOnlyCommands + count test update |
838a4d39a (HOTKEYS #3638) | Map-shaped reply via ComplexOutput + a *ReplyParser, cluster interface additions, full integration overload set, .env image bump |
6567f2d5e (RediSearch #3375) | Whole new command area: own Redis<Area>CommandBuilder, arguments/reply-parser packages |
Conventions beat precedent. Traced reference commands can predate the
current conventions; when the reference code conflicts with a written rule in
this skill or the linked docs, the rule wins. Example: sintercard(K...)
ships without a single-key overload because it predates the
one-overload-per-varargs rule — a new command mirroring it must still add the
single-argument overload.
Determine the @since version — recipe owned by
.agents/docs/javadoc.md:
mvn help:evaluate -Dexpression=project.version -q -DforceStdoutDrop -SNAPSHOT and the patch digit (7.7.0-SNAPSHOT → @since 7.7).
The evidence is your working context, not a deliverable. Hold it in mind to drive the work — do not paste it back to the maintainer or pause for "spec approval." The only stop for the maintainer is the Phase 1 plan approval; surface genuinely ambiguous design choices there, with the proposed sync signatures, rather than interrupting earlier.
Enter plan mode. Using the evidence, classify the change with the decision tree below and enumerate the exact file-by-file touch list, the test matrix, and the gating annotations. The plan must contain:
*Args
object, use the List<K> shape (no varargs) and list the fixed-arity
convenience overloads instead — both house rules live in "Types & args
conventions". Justify any overload you omit so the maintainer signs off on the
exception. An overload discovered missing in review means reworking all six
flavors.Present the plan and explicitly ask permission to execute before implementing. Do not start editing files until the user approves.
Once approved, copy this checklist into your working notes and tick items off:
Extend-commands progress:
- [ ] 0. Evidence: HLD, server PR, live probe + showcase, RESP2/RESP3 replies, @since
- [ ] 1. Plan approved — incl. the sync signature(s), the API contract
- [ ] 2. Types: argument & response types (they must exist before any interface edit)
- [ ] 3. Sync interface: full overload set (varargs → single-arg too) + Javadoc
(@param constraints + @throws for builder-validated preconditions)
- [ ] 4. Mirror: async, reactive, Kotlin, NodeSelection×2 — consistency tests pass
- [ ] 5. Implementations: CommandType/Keyword, builder, async, reactive, Kotlin impl
- [ ] 6. Tests: args/builder/output unit tests + integration base/overloads
- [ ] 7. Docs: entry in the current-release section of docs/new-features.md
- [ ] 8. Verify: mvn clean test + a single integration test run; then make stopA. Extension of an existing command that fits an existing *Args class
(new option token / new field):
*Args class (+ CommandKeyword for new tokens) + tests. Do NOT
touch the command interfaces, builder signatures, or dispatch layers — the
existing args.build(commandArgs) delegation carries the new option through
automatically (cf. the XAddArgs part of the stream-idempotency PR).this; register new tokens in
src/main/java/io/lettuce/core/protocol/CommandKeyword.java.B. New command(s) in an existing group — core or module area — the FULL
matrix, in this order (types first — every flavor references them, so they must
exist to compile). For a command joining an existing module area (a new
FT.* method in the Search group, a new JSON.* method, …) the same matrix
applies with the area substitutions: the group is the area's flavor interfaces,
the builder is the area's Redis<Area>CommandBuilder (+ its
Redis<Area>CommandBuilderUnitTests), argument/reply types go in the area
package, and gating/tests follow the module rules in D (capability probe, stack
node). The dispatch layers are the same AbstractRedisAsyncCommands /
AbstractRedisReactiveCommands and Kotlin *Impl.kt as for core commands.
Argument/response types — see "Types & args conventions" below.
Sync interface src/main/java/io/lettuce/core/api/sync/<Group>Commands.java
— pick the group by command family (STRING → RedisStringCommands, HASH →
RedisHashCommands, generic-key → RedisKeyCommands, …). This is the reference
signature + Javadoc all flavors mirror (see the
writing-javadoc skill; @since mandatory):
/**
* Returns the length of the string value stored at {@code key}.
*
* @param key the key, must not be {@code null}.
* @return the length of the string at {@code key}, or {@code 0} when {@code key} does
* not exist.
* @since 7.7
*/
Long strlen(K key);Three contract rules to apply while designing the signatures and their Javadoc:
*Args object take the keys as
List<K>, not varargs. A varargs parameter must come last, so a trailing
options object can only follow it via an awkward leading placement (cf. the
older sintercard(long limit, K... keys)). For new commands, take the keys
as List<K> so the *Args argument comes last —
sunioncard(List<K> keys, SUnionCardArgs args) — and add fixed-arity
convenience overloads ((K key1, K key2) and their *Args variants)
instead of a varargs form. Since there is no varargs parameter here, the
single-argument-overload rule below does not apply; add only the overloads
that are meaningful — e.g. no single-key sunioncard/sdiffcard, whose
one-key union/difference is just SCARD.foo(K key, V value) alongside foo(K key, V... values). This is a hard
convention for new commands and overrides any traced precedent that lacks
it (older commands predate the rule). Does not apply to the List<K>-shaped
multi-key-with-*Args commands above, which take no varargs.@param
text with the house phrases (must not be {@code null}.,
must not be empty.) and documented with a matching
@throws IllegalArgumentException if … tag — forms owned by
.agents/docs/javadoc.md. Both are then
mirrored to every flavor.Mirror to every flavor: async, reactive, Kotlin coroutines, and the two
cluster node-selection interfaces (NodeSelection<Group>Commands /
NodeSelection<Group>AsyncCommands), applying the per-flavor return-type
mapping rules from
.agents/docs/api-consistency.md.
Protocol enums — command name in
src/main/java/io/lettuce/core/protocol/CommandType.java (wire bytes derive
from the enum name); subcommand tokens in CommandKeyword. Never add a
CommandKeyword that duplicates a name already in CommandType (e.g. SET,
DISCARD) — the builder static-imports both enums and the bare name becomes
ambiguous; reference CommandType.<NAME> directly instead.
Builder — RedisCommandBuilder.java (or the area builder, see D): null
checks via LettuceAssert/notNullKey, CommandArgs in wire order, the
CommandOutput chosen from the observed RESP2/RESP3 replies:
public Command<K, V, Long> strlen(K key) {
notNullKey(key);
return createCommand(STRLEN, new IntegerOutput<>(codec), key);
}
public Command<K, V, Boolean> copy(K source, K destination, CopyArgs copyArgs) {
LettuceAssert.notNull(source, "Source " + MUST_NOT_BE_NULL);
LettuceAssert.notNull(destination, "Destination " + MUST_NOT_BE_NULL);
CommandArgs<K, V> args = new CommandArgs<>(codec).addKey(source).addKey(destination);
copyArgs.build(args);
return createCommand(COPY, new BooleanOutput<>(codec), args);
}Every LettuceAssert precondition written here is public contract: if the
interface Javadoc (step 2) does not already state the constraint and its
@throws IllegalArgumentException, go back and add it — on every flavor.
Dispatch layers — one-liners in both AbstractRedisAsyncCommands and
AbstractRedisReactiveCommands (createMono for scalars,
createDissolvingFlux for List/Set replies, matching the interface's
Mono/Flux):
// AbstractRedisAsyncCommands
public RedisFuture<Long> strlen(K key) { return dispatch(commandBuilder.strlen(key)); }
// AbstractRedisReactiveCommands
public Mono<Long> strlen(K key) { return createMono(() -> commandBuilder.strlen(key)); }Kotlin impl —
src/main/kotlin/io/lettuce/core/api/coroutines/<Group>CoroutinesCommandsImpl.kt:
override suspend fun strlen(key: K): Long = ops.strlen(key).awaitSingle()Cluster — pick the routing shape deliberately; there are three cases:
dbsize, flushall) needs hand-coded fan-out
overrides in RedisAdvancedClusterAsyncCommandsImpl and its reactive
sibling (executeOnUpstream + a MultiNodeExecution aggregator), and may
need methods on the cluster aggregate interfaces.default overrides on
the cluster aggregate interfaces that throw UnsupportedOperationException
and direct callers to the node-selection API or getConnection(nodeId)
(cf. RedisClusterCommands.hotkeysReset()); only the node-selection
flavors execute it.See "Cluster routing" in .agents/docs/architecture.md.
Read-only command? Register it in
src/main/java/io/lettuce/core/protocol/ReadOnlyCommands.java (CommandName
enum) so replica-read routing knows, and bump the size assertion in
ClusterReadOnlyCommandsUnitTests.
C. Extension needing new overloads / a new *Args class (hybrid): the new
methods go through the full matrix of B; the option plumbing follows A. Check
whether command helpers must follow (ScanIterator/ScanStream/ScanFlow for
scan-family commands).
D. New command group / module area (Search/JSON/Bloom/VectorSet-style):
CommandInterfaces enum
(src/test/java/io/lettuce/core/api/consistency/), and wire the group into the
hand-written aggregate interfaces (RedisCommands, RedisAsyncCommands,
RedisReactiveCommands, and the cluster variants) so they extend it — the
consistency tests enforce the aggregate wiring.Redis<Area>CommandBuilder, cf.
RediSearchCommandBuilder) with a matching
Redis<Area>CommandBuilderUnitTests, and keep their argument types and reply
parsers in an area package (e.g. core/search/arguments/).@EnabledOnCommand("FT.CREATE")-style probes; integration tests target the
stack node.*Args implements CompositeArgument
class (e.g. io.lettuce.core.CopyArgs) whose build(CommandArgs) appends its
tokens. Fluent setters return this. If two overloads share options but differ
in a typed field (long vs double), use a self-typed abstract base
(BaseFooArgs<T extends BaseFooArgs<T>>) with concrete subclasses — cf.
BaseIncrexArgs/IncrexArgs/IncrexFloatArgs.@since goes on every new public element, not just the class. A
class-level @since is not inherited: the nested Builder type, each of
its static factory methods, and each public fluent setter needs its own
@since tag, or the generated API docs lose the release provenance for those
members.XNackMode).Value, KeyValue,
ScoredValue, GeoCoordinates, GeoWithin, StreamMessage, KeyScanCursor
(all in io.lettuce.core) — and add a new one only when the reply genuinely
doesn't map. For a map-shaped/structured reply, pair a model class with a
ComplexDataParser consumed via ComplexOutput (cf. HotkeysReply +
HotkeysReplyParser).1/0 integer reply →
Boolean (cf. copy, expire, hsetnx); count → Long; status → String;
bulk value → V. And the overload rules from step B.2: every varargs
parameter also gets a single-argument overload, while a multi-key command with
an *Args object takes List<K> (not varargs) plus fixed-arity overloads.CommandOutput (the reply parser) is chosen at the builder step from the
observed RESP2/RESP3 replies of Phase 0 — if none fits, add one under
io.lettuce.core.output with a unit test (cf. IncrexLongOutput).After mirroring, run:
mvn -Dtest='*ConsistencyUnitTests,CommandBuilderCoverageUnitTests' \
-Dsurefire.failIfNoSpecifiedTests=false testIt names exactly the flavor/signature you missed. For a genuinely unusual return
type (e.g. Flux<Value<Long>>, or Mono<List<Double>> because Redis returns
nulls), register it in the registry that owns the flavor —
src/test/java/io/lettuce/core/api/consistency/KnownApiDeviations.java for the
Java flavors, src/test/kotlin/io/lettuce/core/api/consistency/KnownKotlinApiDeviations.kt
for the coroutine flavor — with a comment justifying it. Never use a
deviation entry to paper over a sync/async signature mismatch — that breaks the
sync-over-async runtime proxy.
Format before you build: run mvn formatter:format after hand-editing — the
build's formatter:validate step fails the compile on unformatted code. Do not
submit formatting-only diffs.
Naming, placement, and the base/overload structure are owned by .agents/docs/integration-testing.md — follow it. The established per-command layers (write all that apply):
*Args classes): assert the exact encoded tokens and
wire order, setter validation, and overload equivalence — e.g.
IncrexArgsUnitTests, XAddArgsUnitTests. No server needed.src/test/java/io/lettuce/core/RedisCommandBuilderUnitTests.java; area
commands in their Redis<Area>CommandBuilderUnitTests.CommandOutput was added (cf.
IncrexOutputUnitTests).<Group>CommandIntegrationTests), gated per-test with
@EnabledOnCommand("<NAME>"). Use assertions derived from the redis-cli
showcase transcripts — real semantics, not just "no error", covering the whole
family the option touches (with/without optional args, error cases):@Test
@EnabledOnCommand("COPY")
void copy() {
redis.set(key, value);
assertThat(redis.copy(key, key + "2")).isTrue();
}@Test methods re-run automatically under the
group's existing RESP2/cluster/reactive/Tx overload classes — but only the
ones that exist. Check the target group against peer groups and create a
missing overload class when it matters for the command (INCREX created
StringCommandResp2IntegrationTests because its reply differs by protocol).
Provide the base test at minimum; add overloads that carry real
risk (RESP2 when replies differ, cluster when routing matters).The build pins a specific JDK to match CI — check .github/workflows/ and the
local-gotchas section of
.agents/docs/integration-testing.md
(pin JAVA_HOME, worktree git-commit-id-plugin skip, TEST_WORK_FOLDER).
mvn clean test, or mvn -Dtest=FooUnitTests test.verify
lifecycle — -Dit.test= filters Failsafe, -Dtest= does not:TEST_WORK_FOLDER=./work/docker mvn -DskipITs=false -DskipUnitTests=true \
-Dit.test=FooIntegrationTests verify -Pciredislabs/client-libs-test tag yet, say
so: the integration tests will be skipped by @EnabledOnCommand (expected and
acceptable), but they must still be written and compile.Tear the environment down when you are done. The Docker topology started in Phase 0 keeps running (and holds the test ports) until stopped. After the final verification run — and equally when the task is aborted or fails partway — run:
make stopCommandBuilderCoverageUnitTests pass.*Args object uses List<K> (not varargs) with
fixed-arity overloads — mirrored across all flavors (or a
maintainer-approved justification from the plan).@since on every new public element — including the nested Builder,
static factories, and fluent setters of new *Args classes; class-level
tags are not inherited (see
.agents/docs/javadoc.md). Javadoc written on
the sync interface and mirrored with flavor-appropriate @return phrasing.@param
constraint phrases + @throws IllegalArgumentException if ….CommandKeyword constants; no keyword duplicating a CommandType.ReadOnlyCommands (+ count test bumped).mvn formatter:format run; no formatting-only noise in the diff.@EnabledOnCommand; missing
integration overload classes created where the command needs them.docs/ (MkDocs) updated — a new command or option is user-facing: add
a one-line entry to the current-release section of docs/new-features.md
(follow its existing "Support for [X](redis.io link) …" pattern), plus
any feature page the change affects..env.vX.XX image pin bumped if the feature needed a newer server build.make stop) after the final verification
run.CommandOutput and the
reactive mapping. Confirm against a running server, don't assume.AbstractRedisAsyncCommands and
AbstractRedisReactiveCommands, plus the Kotlin *Impl.kt.src/test/java/io/lettuce/core/api/ because an old reference PR touched them.CommandArgs order or CommandOutput, missing @since, missing
@EnabledOnCommand gating, or missing the read-only registry entry.sintercard(K...) doesn't have one, or
stopping at a class-level @since because an old *Args class did. Older
code predates the rules; the conventions win.© redis, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in .agents/skills/extend-commands-api of redis/lettuce.
Open the folder on GitHubat commit 114a3ef
Extend Commands API next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Extend Commands API this skillredis/lettuce | 5.8k | — | ~7.7k | Automated safety check: Notes | MIT | |
| Extend Commands APIredis/jedis | 12k | — | ~7.2k | Automated safety check: Warn | MIT | |
| Writing Testsvert-x3/vertx-redis-client | 142 | — | ~1.6k | Automated safety check: Pass | Apache-2.0 | |
| Azure Upgrademicrosoft/GitHub-Copilot-for-Azure | 255 | 1 repos | ~1.5k | Automated safety check: Pass | MIT | |
| AWS SDK Java V2 Dynamodbgiuseppe-trisciuoglio/developer-kit | 355 | 1 repos | ~3.3k | Automated safety check: Notes | MIT | |
| Add Garnet RESP Commandmicrosoft/garnet | 12k | — | ~9.7k | Automated safety check: Pass | MIT |
redis/jedis
Add or extend Redis commands in the Jedis client API — a new core command, a family of new commands, an extension to an existing command's options, or a module command (Search/TimeSeries/JSON/Bloom).
vert-x3/vertx-redis-client
Testing patterns for Vert.x Redis Client: test frameworks, async testing, test locations, container setup, and how to run tests.
microsoft/GitHub-Copilot-for-Azure
Assess and upgrade Azure workloads between plans, tiers, or SKUs, or modernize Azure SDK dependencies in source code.
giuseppe-trisciuoglio/developer-kit
Provides Amazon DynamoDB patterns using AWS SDK for Java 2.x.
microsoft/garnet
Step-by-step guide for adding a new built-in RESP command to Garnet, from the command enum and parser to storage callbacks, command metadata JSON and tests.
jabrena/plinth
A skill your agent uses when you need to write or improve integration tests — including Testcontainers with @ServiceConnection, @DataJdbcTest persistence slices, TestRestTemplate or MockMvcTester…
redis/lettuce
A skill your agent uses when writing or editing Javadoc for Lettuce public API — new methods, classes, deprecations, or when a reviewer asks to fix or improve doc comments.
Categories
Add or extend Redis commands in the Lettuce client API end-to-end — a new core command, a family of new commands, an extension to an existing command's options, or a module/area command…. Extend Commands API is an agent skill from redis/lettuce, published by the product's own GitHub organization. Add or extend Redis commands in the Lettuce client API end-to-end — a new core command, a family of new commands, an extension to an existing command's options, or a module/area command (Search/JSON/Bloom/VectorSet).
Extend Commands API fits situations like: add support for the <X command; implement <REDIS COMMAND in Lettuce; extend <command with <option; adding a new argument/overload to an existing command.
Run `npx skills add redis/lettuce --skill extend-commands-api -a claude-code`. Or copy the skill folder (.agents/skills/extend-commands-api in redis/lettuce) into .claude/skills/extend-commands-api in your project. Claude Code loads it when a task matches its description.
Run `npx skills add redis/lettuce --skill extend-commands-api -a codex`. Or copy the skill folder (.agents/skills/extend-commands-api in redis/lettuce) into .agents/skills/extend-commands-api in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add redis/lettuce --skill extend-commands-api -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/extend-commands-api, .gemini/skills/extend-commands-api, .github/skills/extend-commands-api and .opencode/skills/extend-commands-api in your project.
Going by SKILL.md and its folder, Extend Commands API needs the command-line tools its instructions call (mvn, make, gh and redis-cli). Our summary lists: Docker. Its frontmatter pre-approves these tools: Bash(mvn *), Bash(make *), Bash(redis-cli *), Bash(gh *).
SKILL.md names 1 domain. As links in the text: hub.docker.com. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found notes only (mentions a .env file), nothing it rates as a warning. It is not a guarantee. Review the folder before installing.
Extend Commands API is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 7.7k tokens (SKILL.md is roughly 31k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Extend Commands API: Extend Commands API (redis/jedis, 12k stars), Writing Tests (vert-x3/vertx-redis-client, 142 stars), Azure Upgrade (microsoft/GitHub-Copilot-for-Azure, 255 stars) and AWS SDK Java V2 Dynamodb (giuseppe-trisciuoglio/developer-kit, 355 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
redis (a GitHub organization, an official publisher) maintains it in redis/lettuce, which has 5,780 GitHub stars. The repository holds 2 skills in this directory. The repository was last updated on October 7, 2026.
Source: redis/lettuce on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.