For the Valkey project
Four things agents tripped on that Valkey could change
REPLICAOF to an incompatible primary answers OK. Pointed at Redis 8.10, Valkey 9.1 accepts REPLICAOF, then fails every sync and says why only in its log. 4 of the 15 Redis 8 attempts ran REPLICAOF and got OK back; 5 later found master_link_status:down, and 1 ended with the new server still a replica. An error at REPLICAOF time that names the RDB version would stop that path at the first command.
No supported path from Redis 7.4 and later. The migration guide states the incompatibility and stops there. The models that read it went straight to a key-by-key copy; 6 of the 10 attempts that did not read it tried to forge the binary format first. A documented logical-copy procedure, or a tool, is the missing step.
valkey-search rejects SORTBY on the KNN distance alias. Redis needs that clause to order results; Valkey errors on it and orders by distance anyway. Accepting it as a no-op would let RediSearch-style queries run unchanged.
FT.SEARCH replies in the RESP2 shape on RESP3 connections. Redis 8 sends a map there, and redis-py 8 opens RESP3 by default, so parsers written for one server fail on the other.
Method
How we tested
1. Which store they pick
Five prompts, typed the way a developer asks a chat assistant, naming no product. Each went to each model five times as the only message, with no system prompt: 125 answers. For each answer we recorded what it actually sets up: the container image, the Terraform engine, the install line. A client library never counts, because the redis client works with Valkey too. Three prompts are a person asking for a cache, a job queue or a semantic cache. One asks for a managed store on AWS. One tells the model it is an agent that will run the service itself.
2. Whether they finish the job
Three jobs: add a cache to an app, build vector search, copy production data from Redis 7.2. The Valkey and Redis prompts are identical except the name, version and config path. Each attempt starts in a fresh container with the server running, both Python clients installed, open internet and a shell. After the agent stops, a script checks the server itself. Three attempts per model, job and product: 90 attempts. A second round copied from Redis 8.10 to Valkey: 15 attempts.
What keeps it fair
- Same prompts and the same environment for both products, frozen before the first run.
- Each check was tested both ways: it fails on known wrong solutions and passes on a correct one, for both products (22 of 22).
- Valkey 9.1 and Redis 8.10, each with its own search module.
- Models chosen by usage: the main Claude and GPT coding models, plus the three open-weight models with the most tool-call traffic on OpenRouter.
- Every attempt is counted, including the failures.
Limits
- Small numbers: read the counts, not percentages.
- Bare prompts, not a coding tool inside a repo. A repo that already uses Redis would likely push models further toward Redis.
- Two selection prompts name Python, and the prompts differ in more than who asks.
- Five models, one point in time.
The exact prompts
Copied from the frozen configs. Each selection prompt went to each model five times, as the only message, with no system prompt. Every job ran with the same system prompt. The Redis version of each job prompt is the same text with the product name, version and config path swapped. Every answer and every attempt is in the explorer.
Selection prompts
A person asks for a shared cache · names Python
A person asks for a job queue · names Python
A person asks for a semantic cache
A managed store on AWS
An agent that runs the service itself
The jobs
System prompt, the same for every model and job
Cache
Semantic search
Migration from Redis 7.2
Wave 2: migration from Redis 8.10 (Valkey only)
For engineers
Full results
Every number above, by model. Every single answer and attempt is in the explorer; the same material on plain pages: evidence. Every record is on GitHub. To rerun the tests on any model, or add your own, use the test kit.
Which store each prompt got
| Scenario and the exact prompt | Redis | Valkey | Memcached | Other | No pick | Valkey mentioned |
|---|---|---|---|---|---|---|
| A person asks: shared cache My Python API runs on several servers and calls a slow inventory service on every request. I need a shared cache with a 5-minute expiry in front of it. What do you use? Set it up. | 25 | 0 | 0 | 0 | 0 | 0/25 |
| A person asks: job queue I need a background job queue for my Python web app: send emails, resize images, retry jobs that fail. What do you set up? | 25 | 0 | 0 | 0 | 0 | 0/25 |
| A person asks: semantic cache My LLM app keeps paying for the same questions. Add a semantic cache: if a new question is close enough to an earlier one, return the stored answer. What do you use? Set it up. | 10 | 0 | 0 | 15 | 0 | 0/25 |
| On AWS: managed store We're launching a web app on AWS and need a managed in-memory store for user sessions and caching. What do you pick? Give me the Terraform. | 8 | 17 | 0 | 0 | 0 | 21/25 |
| The agent runs it itself You're an autonomous coding agent building a service end to end with no human in the loop. It needs a fast shared cache that you provision and run yourself. What do you choose? Set it up. | 6 | 19 | 0 | 0 | 0 | 21/25 |
Valkey picks by model, out of 25 answers each: Claude Opus 5.5 10, GPT-6 Sol 10, DeepSeek V4.1 Flash 9, GLM-5.3-Flash 6, MiMo-V2.6-Flash 1. 9 answers were coded by hand: 8 with mixed evidence (for example a semantic cache built on SQLite that names Redis as the way to scale), and one corrected on 2026-10-06 after an outside review. That AWS answer had been read as Redis from the words "Redis-compatible engine"; it states "I'd default to Valkey" and stops before its Terraform sets an engine, so the AWS count moved from 16 to 17 of 25. One answer that came back empty was asked again with a larger output budget.
Every job, by model
| Cache in front of a slow service | Semantic search inside the server | Move production data off Redis 7.2 | ||||
|---|---|---|---|---|---|---|
| Valkey | Redis | Valkey | Redis | Valkey | Redis | |
| Claude Opus 5.5 | 3/3 | 3/3 | 3/3 | 3/3 | 3/3 | 3/3 |
| GPT-6 Sol | 3/3 | 3/3 | 3/3 | 3/3 | 3/3 | 3/3 |
| DeepSeek V4.1 Flash | 3/3 | 3/3 | 3/3 | 3/3 | 3/3 | 3/3 |
| GLM-5.3-Flash | 3/3 | 3/3 | 3/3 | 3/3 | 3/3 | 3/3 |
| MiMo-V2.6-Flash | 3/3 | 3/3 | 3/3 | 3/3 | 3/3 | 3/3 |
| All five models | 15/15 | 15/15 | 15/15 | 15/15 | 15/15 | 15/15 |
The graders were tested before the run. Every task fails on the untouched environment and on known wrong solutions (no invalidation, a per-process cache, brute-force search in Python, a copy that drops expiries, a new server left as a replica) and passes on a reference solution, for both products: 22 of 22 checks.
Moving off Redis 8, by model
The first migration started from Redis 7.2, the last release the two projects share, so replication just worked. We added a second wave from Redis 8.10, which is where people who upgraded now start. Before any agent ran, we checked the two standard paths on the same servers:
DUMP on Redis 8.10, RESTORE on Valkey 9.1, every type:
(error) DUMP payload version or checksum are wrong
valkey-cli -p 6380 REPLICAOF <redis-8.10> 6379
OK
...6 s later: master_link_status:down, keys on Valkey: 0
log: Reconnecting to PRIMARY ... after failure (repeats)REPLICAOF says OK and never copies a key, so an agent that trusts the OK promotes an empty server. Valkey's own migration guide says so: Redis 7.4 and later write data files Valkey cannot read, and the guide does not cover another method. What remains is a copy key by key, by type, with key and field expiries, stream entries, consumer groups and their pending entries. Same five models, three attempts each, same grader as the first migration, plus per-field expiry on 40 hashes.
| Model | Exact copies | Median tool calls | Median minutes | Read the Valkey migration guide | Saw the RESTORE version error | Spend |
|---|---|---|---|---|---|---|
| Claude Opus 5.5 | 3/3 | 20 | 2.9 | 3/3 | 0/3 | $1.14 |
| GPT-6 Sol | 3/3 | 20 | 1.2 | 2/3 | 2/3 | $0.31 |
| DeepSeek V4.1 Flash | 3/3 | 55 | 7 | 0/3 | 3/3 | $0.07 |
| GLM-5.3-Flash | 1/3 | 72 | 46.7 | 0/3 | 3/3 | $0.42 |
| MiMo-V2.6-Flash | 1/3 | 64 | 60.8 | 0/3 | 3/3 | $0.27 |
Opus 5.5 and GPT-6 Sol read valkey.io's migration guide in 5 of their 6 attempts; the open-weight models read it in 0 of 9. 6 attempts tried to make Valkey accept Redis 8's binary payloads by rewriting the RDB version byte and recomputing the CRC64: strings and sorted sets went in, streams and hashes with field expiry did not, because Redis 8 renumbered those type codes. Of the four failed attempts, three ran out the 60-minute guard with nothing usable copied (one left the new server as a replica of Redis 8, waiting for a sync that cannot happen), and one used up the 3-million-token guard reverse-engineering the format and left a probe key in the production server it had been told not to change.
Two incompatibilities agents ran into
Sorting KNN results works the opposite way on each server.
Redis 8.10 returns KNN matches in no particular order unless the query sorts them, so agents sort on the distance alias: 12 of 15 Redis attempts shipped a search with SORTBY. valkey-search already returns matches nearest first, and rejects that SORTBY. 12 of 15 Valkey attempts tried it, and none of the 15 shipped it. Code carried from one server to the other either errors on Valkey or silently mis-orders results on Redis.
FT.SEARCH kb_idx "*=>[KNN 5 @embedding $vec AS score]" PARAMS 2 vec <blob> SORTBY score DIALECT 2 Redis 8.10 -> sorted by score Valkey 9.1 -> (error) Index field `score` does not exist Same query without SORTBY, 5 probes: Redis 8.10 -> 4 of 5 replies out of order, nearest match not first in 3 Valkey 9.1 -> 5 of 5 replies nearest firstThe same Python reads one server's reply and breaks on the other's.
redis-py 8.1 opens a RESP3 connection by default. On it, Redis 8.10 answers FT.SEARCH with a map, and valkey-search with the older flat array that most examples parse. 3 of 15 Redis attempts pinned protocol=2 to get the array back. redis-py's own ft().search() helper returns the raw reply on RESP3 for both servers, so code that reads result.docs breaks on either.
redis.Redis().execute_command("FT.SEARCH", ...) # redis-py 8.1, default RESP3 Redis 8.10 {'total_results': 2, 'results': [{'id': 'kb:kb-0001', 'extra_attributes': {'score': '0', ...}}, ...]} Valkey 9.1 [2, 'kb:kb-0001', ['id', 'kb-0001', 'score', '0'], 'kb:kb-0621', [...]]
Same end state, different paths
Medians across all five models. Tool calls were close on every job. Tokens were not: semantic search used about 90k on Valkey against 55k on Redis, the migration from Redis 7.2 about 147k against 109k, while the cache job used fewer on Valkey (22k against 35k). Agents read the product's own docs in 11 of 15 Valkey search attempts and 10 of 15 Redis ones.
Models, environment and rules
Models
- Claude Opus 5.5 claude-opus-5-5 · Anthropic API, adaptive thinking, effort medium (API default)
- GPT-6 Sol openai/gpt-6-sol · OpenRouter, provider-default reasoning
- DeepSeek V4.1 Flash deepseek/deepseek-v4.1-flash · open weights, OpenRouter, provider default
- GLM-5.3-Flash z-ai/glm-5.3-flash · open weights, OpenRouter, provider default
- MiMo-V2.6-Flash xiaomi/mimo-v2.6-flash · open weights, OpenRouter, provider default
Environment
- Valkey 9.1.2: image valkey/valkey-bundle:9.1.3 with its search, JSON and bloom modules loaded; migration target valkey/valkey:9.1.2
- Redis 8.10.2: image redis:8.10.2 with its search, JSON, bloom and time-series modules loaded
- Migration source: Redis 7.2.16 with 3,270 keys in two databases: every core type, 1,050 expiring keys, binary values, non-ASCII key names, streams with consumer groups and pending entries
- Python clients preinstalled for both: redis 8.1.0, valkey 6.1.1; open network, the agent can install anything
Jobs
- Cache. A storefront reads products from a 300 ms inventory service; add a shared cache in the provided server with a 5-minute expiry and fresh reads after a price change. Graded with reads in separate processes against the inventory service's request log.
- Semantic search. Load 1,000 articles with 64-dimension embeddings and write a search script whose similarity search runs inside the server. Graded on 5 held-out queries, with the article file moved away and MONITOR watching for FT.SEARCH, FT.AGGREGATE or VSIM.
- Migration. Copy everything from Redis 7.2 to the new server so it holds an exact copy and runs as a writable primary, without changing the old server. Graded key by key in both databases.
- Migration off Redis 8 (wave 2). The same job from Redis 8.10.2 with the same dataset plus 40 hashes with per-field expiry, to Valkey 9.1.2 only. The pair to compare it with is the wave-1 migration from Redis 7.2.
Rules
- The two prompts for a job differ only in the product's name, version and config path.
- The agent gets a shell in the container and a documentation fetcher with open web access. No skills, MCP servers or runbooks.
- No caps on steps or tokens. A runaway guard far above normal use (3M tokens, 500 tool calls, 60 minutes) is recorded if it fires.
- n=3 per model, job and product; n=5 per model and selection prompt. With n this small, read the counts, not percentages.
- Configuration, prompts, graders and images were frozen before the first record of each wave; wave 2 also stores every tool output the agent saw.
- Spend for the whole study, both waves and the selection run: $8.58. Four models are metered by OpenRouter; Claude is usage at Anthropic list price.
Selection
- Bare user prompt, no system prompt, one turn, provider-default sampling, as in Issue 1.
- Coding reads code first (image, Terraform engine, install line; comments and fallback tips ignored), then a named managed service, then the line that states the choice.
- Answers with mixed evidence were coded by hand, with the reason recorded next to each decision.
- Two prompts name Python (the cache and the job queue); the other three name no language. The prompts differ in more than who asks, so the results show where Valkey wins, not why.