
Redis Core
- 1.6k installs
- 94 repo stars
- Updated July 9, 2026
- redis/agent-skills
redis-core is a Redis skill for data structure selection and key naming conventions.
About
The redis-core skill provides foundational Redis modeling guidance for choosing among String, Hash, List, Set, Sorted Set, JSON, Stream, and Vector Set structures plus consistent colon-separated key naming. It helps agents design keys and structures that scale without hot-key anti-patterns or ambiguous namespaces. Patterns cover caching, leaderboards, queues, pub/sub, and vector search use cases with structure-specific tradeoffs. Agents apply redis-core before implementing Redis clients in application backends. Redis structure selection: String, Hash, List, Set, ZSet, JSON, Stream, Vector. Colon-separated consistent key naming conventions. Caching, queues, leaderboards, and vector search patterns. Scalable data model guidance without hot-key pitfalls. Foundational Redis modeling before client implementation. Choose Redis data structures and colon-separated key naming for scalable data models.
- Redis structure selection: String, Hash, List, Set, ZSet, JSON, Stream, Vector.
- Colon-separated consistent key naming conventions.
- Caching, queues, leaderboards, and vector search patterns.
- Scalable data model guidance without hot-key pitfalls.
- Foundational Redis modeling before client implementation.
Redis Core by the numbers
- 1,649 all-time installs (skills.sh)
- +177 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #299 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
What redis-core says it does
choose the right data structure (String, Hash, List, Set, Sorted Set, JSON, Stream, Vector Set) and use consistent colon-separated key names
npx skills add https://github.com/redis/agent-skills --skill redis-coreAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1.6k |
|---|---|
| repo stars | ★ 94 |
| Last updated | July 9, 2026 |
| Repository | redis/agent-skills ↗ |
Which Redis data structure and key pattern fits this use case?
Choose Redis data structures and colon-separated key naming for scalable data models.
Who is it for?
Backend developers designing Redis caches, queues, or vector indexes.
Skip if: Skip when only Redis admin ops without application data modeling.
When should I use this skill?
User designs Redis keys, picks data structures, or models Redis schemas.
What you get
Redis schema with appropriate structures and colon-separated key names.
- Key naming schema
- Data structure selection guide
- TTL and memory plan
By the numbers
- Skill version 1.0.0 from redis/agent-skills
Files
Redis Core
Foundational guidance for modeling data in Redis. Covers data-type selection and key-name conventions — the two decisions that most directly drive memory, performance, and maintainability.
When to apply
- Caching objects, sessions, or per-user state.
- Counters, leaderboards, recent-items lists, unique-membership sets.
- Reviewing or refactoring Redis key names.
- Deciding between a Redis Hash and a JSON document for an entity.
1. Choose the right data structure
Pick the type that matches the access pattern, not just the shape of the data.
| Use case | Recommended type | Why |
|---|---|---|
| Simple values, counters | String | Atomic INCR/DECR, SET/GET |
| Object with independently updated fields | Hash | Per-field reads/writes, no whole-object rewrite |
| Queue, recent-N items | List | O(1) push/pop at ends |
| Unique items, membership checks | Set | O(1) SADD/SISMEMBER/SCARD |
| Rankings, score-based ranges | Sorted Set | Score-ordered; ZADD/ZRANGE/ZRANK |
| Nested / hierarchical data | JSON | Path-level updates, nested arrays, RQE indexing |
| Event log, fan-out messaging | Stream | Persistent, consumer groups |
| Vector similarity | Vector Set | Native vector storage with HNSW |
Common anti-pattern: stuffing a flat object into a serialized string. Updating one field means fetch + parse + mutate + rewrite. Use a Hash instead.
See references/choose-data-structure.md for full rationale and Python/Java examples.
2. Use consistent key names
Use colon-separated segments with a stable hierarchy:
{entity}:{id}:{attribute}
user:1001:profile
user:1001:settings
order:2024:items
session:abc123
article:987:likes
game:space-invaders:leaderboardRules of thumb:
- Lowercase, colon-separated. No spaces, no mixed casing (
User_1001_Profileis bad). - Keep keys short but readable — keys live in memory and appear in every command.
- Don't use full URLs or long strings as keys. Extract a short identifier, or use a hash digest of the URL.
- Prefix for multi-tenancy (
tenant:42:user:7:cart) so scans and ACLs can target a tenant cleanly. - Be consistent. Pick one convention per service and apply it across all keys.
See references/key-naming.md for cleanup examples and edge cases.
References
{
"name": "redis-core",
"version": "1.0.0",
"description": "Core Redis modeling — data structures, key naming, memory and TTL, atomic primitives, JSON vs Hash, Streams vs Pub/Sub.",
"author": {
"name": "Redis",
"email": "support@redis.com"
},
"homepage": "https://redis.io",
"repository": "https://github.com/redis/agent-skills",
"license": "MIT",
"keywords": ["redis", "database", "data-modeling", "data-structures", "key-naming"]
}
{
"generated_at": "2026-05-22T10:36:23.032Z",
"input_root": "eval-workspaces/redis-core/core/iteration-1",
"context": {
"skill_name": "redis-core",
"suite_name": "core"
},
"models": [
{
"model_dir": "anthropic__claude-haiku-4-5-20251001",
"model": "claude-haiku-4-5-20251001",
"provider": "anthropic",
"analyzer_model": "<model-name>",
"runs_per_configuration": 3,
"evals_run": [
1,
2,
3,
4
],
"without_skill": {
"count": 8,
"pass_rate": 0.95,
"time_seconds": 9.009375,
"tokens": 1156.125
},
"with_skill": {
"count": 8,
"pass_rate": 0.95,
"time_seconds": 18.1815,
"tokens": 1080.75
},
"delta": {
"pass_rate": 0,
"time_seconds": 9.172125,
"tokens": -75.375
},
"cost": {
"generation_usd": 0.608038,
"grading_usd": 1.513413,
"total_usd": 2.121451,
"with_skill_usd": 1.227107,
"without_skill_usd": 0.894344,
"delta_usd": 0.041595,
"runs_with_cost": 16
},
"verdict": "neutral"
},
{
"model_dir": "anthropic__claude-opus-4-7",
"model": "claude-opus-4-7",
"provider": "anthropic",
"analyzer_model": "<model-name>",
"runs_per_configuration": 3,
"evals_run": [
1,
2,
3,
4
],
"without_skill": {
"count": 8,
"pass_rate": 0.975,
"time_seconds": 16.212,
"tokens": 1917.375
},
"with_skill": {
"count": 8,
"pass_rate": 1,
"time_seconds": 14.751375,
"tokens": 1203.5
},
"delta": {
"pass_rate": 0.025000000000000022,
"time_seconds": -1.4606250000000003,
"tokens": -713.875
},
"cost": {
"generation_usd": 1.812924,
"grading_usd": 1.542798,
"total_usd": 3.355722,
"with_skill_usd": 1.791716,
"without_skill_usd": 1.564006,
"delta_usd": 0.028464,
"runs_with_cost": 16
},
"verdict": "neutral"
},
{
"model_dir": "anthropic__claude-sonnet-4-6",
"model": "claude-sonnet-4-6",
"provider": "anthropic",
"analyzer_model": "<model-name>",
"runs_per_configuration": 3,
"evals_run": [
1,
2,
3,
4
],
"without_skill": {
"count": 8,
"pass_rate": 0.95,
"time_seconds": 14.230625,
"tokens": 1391.25
},
"with_skill": {
"count": 8,
"pass_rate": 0.975,
"time_seconds": 20.34725,
"tokens": 1254.625
},
"delta": {
"pass_rate": 0.025000000000000022,
"time_seconds": 6.116624999999999,
"tokens": -136.625
},
"cost": {
"generation_usd": 1.00935,
"grading_usd": 1.534102,
"total_usd": 2.543452,
"with_skill_usd": 1.424765,
"without_skill_usd": 1.118687,
"delta_usd": 0.03826,
"runs_with_cost": 16
},
"verdict": "neutral"
}
],
"evals": [
{
"eval_id": 1,
"eval_name": "object-profile-cache",
"without_skill": {
"count": 6,
"pass_rate": 0.8666666666666667,
"time_seconds": 13.931333333333333,
"tokens": 1448.5
},
"with_skill": {
"count": 6,
"pass_rate": 0.9,
"time_seconds": 20.580166666666667,
"tokens": 1201.1666666666667
},
"delta": {
"pass_rate": 0.033333333333333326,
"time_seconds": 6.648833333333334,
"tokens": -247.33333333333326
},
"mean_delta_pass_rate": 0.033333333333333326,
"models": [
{
"model": "claude-haiku-4-5-20251001",
"eval_name": "object-profile-cache",
"with_skill": {
"count": 2,
"pass_rate": 0.8,
"time_seconds": 20.332,
"tokens": 943
},
"without_skill": {
"count": 2,
"pass_rate": 0.8,
"time_seconds": 10.593,
"tokens": 1164.5
},
"delta": {
"pass_rate": 0,
"time_seconds": 9.739,
"tokens": -221.5
}
},
{
"model": "claude-opus-4-7",
"eval_name": "object-profile-cache",
"with_skill": {
"count": 2,
"pass_rate": 1,
"time_seconds": 14.745000000000001,
"tokens": 1362
},
"without_skill": {
"count": 2,
"pass_rate": 1,
"time_seconds": 15.901,
"tokens": 1629.5
},
"delta": {
"pass_rate": 0,
"time_seconds": -1.1559999999999988,
"tokens": -267.5
}
},
{
"model": "claude-sonnet-4-6",
"eval_name": "object-profile-cache",
"with_skill": {
"count": 2,
"pass_rate": 0.9,
"time_seconds": 26.6635,
"tokens": 1298.5
},
"without_skill": {
"count": 2,
"pass_rate": 0.8,
"time_seconds": 15.3,
"tokens": 1551.5
},
"delta": {
"pass_rate": 0.09999999999999998,
"time_seconds": 11.363499999999998,
"tokens": -253
}
}
]
},
{
"eval_id": 2,
"eval_name": "unique-membership",
"without_skill": {
"count": 6,
"pass_rate": 0.9666666666666667,
"time_seconds": 11.048499999999999,
"tokens": 1246.6666666666667
},
"with_skill": {
"count": 6,
"pass_rate": 1,
"time_seconds": 14.267666666666665,
"tokens": 952.3333333333334
},
"delta": {
"pass_rate": 0.033333333333333326,
"time_seconds": 3.2191666666666663,
"tokens": -294.33333333333337
},
"mean_delta_pass_rate": 0.033333333333333326,
"models": [
{
"model": "claude-haiku-4-5-20251001",
"eval_name": "unique-membership",
"with_skill": {
"count": 2,
"pass_rate": 1,
"time_seconds": 15.326,
"tokens": 1283
},
"without_skill": {
"count": 2,
"pass_rate": 1,
"time_seconds": 8.314,
"tokens": 946.5
},
"delta": {
"pass_rate": 0,
"time_seconds": 7.0120000000000005,
"tokens": 336.5
}
},
{
"model": "claude-opus-4-7",
"eval_name": "unique-membership",
"with_skill": {
"count": 2,
"pass_rate": 1,
"time_seconds": 10.7035,
"tokens": 682
},
"without_skill": {
"count": 2,
"pass_rate": 0.9,
"time_seconds": 14.1905,
"tokens": 1787
},
"delta": {
"pass_rate": 0.09999999999999998,
"time_seconds": -3.487,
"tokens": -1105
}
},
{
"model": "claude-sonnet-4-6",
"eval_name": "unique-membership",
"with_skill": {
"count": 2,
"pass_rate": 1,
"time_seconds": 16.7735,
"tokens": 892
},
"without_skill": {
"count": 2,
"pass_rate": 1,
"time_seconds": 10.641,
"tokens": 1006.5
},
"delta": {
"pass_rate": 0,
"time_seconds": 6.1324999999999985,
"tokens": -114.5
}
}
]
},
{
"eval_id": 3,
"eval_name": "leaderboard-ranking",
"without_skill": {
"count": 6,
"pass_rate": 1,
"time_seconds": 12.535833333333334,
"tokens": 1657.1666666666667
},
"with_skill": {
"count": 6,
"pass_rate": 1,
"time_seconds": 17.886166666666664,
"tokens": 1360.8333333333333
},
"delta": {
"pass_rate": 0,
"time_seconds": 5.35033333333333,
"tokens": -296.3333333333335
},
"mean_delta_pass_rate": 0,
"models": [
{
"model": "claude-haiku-4-5-20251001",
"eval_name": "leaderboard-ranking",
"with_skill": {
"count": 2,
"pass_rate": 1,
"time_seconds": 19.6515,
"tokens": 1071.5
},
"without_skill": {
"count": 2,
"pass_rate": 1,
"time_seconds": 8.184999999999999,
"tokens": 1193.5
},
"delta": {
"pass_rate": 0,
"time_seconds": 11.4665,
"tokens": -122
}
},
{
"model": "claude-opus-4-7",
"eval_name": "leaderboard-ranking",
"with_skill": {
"count": 2,
"pass_rate": 1,
"time_seconds": 14.5725,
"tokens": 1447
},
"without_skill": {
"count": 2,
"pass_rate": 1,
"time_seconds": 16.533,
"tokens": 2181
},
"delta": {
"pass_rate": 0,
"time_seconds": -1.9605000000000015,
"tokens": -734
}
},
{
"model": "claude-sonnet-4-6",
"eval_name": "leaderboard-ranking",
"with_skill": {
"count": 2,
"pass_rate": 1,
"time_seconds": 19.4345,
"tokens": 1564
},
"without_skill": {
"count": 2,
"pass_rate": 1,
"time_seconds": 12.8895,
"tokens": 1597
},
"delta": {
"pass_rate": 0,
"time_seconds": 6.545,
"tokens": -33
}
}
]
},
{
"eval_id": 4,
"eval_name": "key-naming-cleanup",
"without_skill": {
"count": 6,
"pass_rate": 1,
"time_seconds": 15.086999999999998,
"tokens": 1600.6666666666667
},
"with_skill": {
"count": 6,
"pass_rate": 1,
"time_seconds": 18.306166666666666,
"tokens": 1204.1666666666667
},
"delta": {
"pass_rate": 0,
"time_seconds": 3.219166666666668,
"tokens": -396.5
},
"mean_delta_pass_rate": 0,
"models": [
{
"model": "claude-haiku-4-5-20251001",
"eval_name": "key-naming-cleanup",
"with_skill": {
"count": 2,
"pass_rate": 1,
"time_seconds": 17.4165,
"tokens": 1025.5
},
"without_skill": {
"count": 2,
"pass_rate": 1,
"time_seconds": 8.9455,
"tokens": 1320
},
"delta": {
"pass_rate": 0,
"time_seconds": 8.471,
"tokens": -294.5
}
},
{
"model": "claude-opus-4-7",
"eval_name": "key-naming-cleanup",
"with_skill": {
"count": 2,
"pass_rate": 1,
"time_seconds": 18.984499999999997,
"tokens": 1323
},
"without_skill": {
"count": 2,
"pass_rate": 1,
"time_seconds": 18.2235,
"tokens": 2072
},
"delta": {
"pass_rate": 0,
"time_seconds": 0.7609999999999957,
"tokens": -749
}
},
{
"model": "claude-sonnet-4-6",
"eval_name": "key-naming-cleanup",
"with_skill": {
"count": 2,
"pass_rate": 1,
"time_seconds": 18.5175,
"tokens": 1264
},
"without_skill": {
"count": 2,
"pass_rate": 1,
"time_seconds": 18.092,
"tokens": 1410
},
"delta": {
"pass_rate": 0,
"time_seconds": 0.42549999999999955,
"tokens": -146
}
}
]
}
],
"overall": {
"models": 3,
"total_cost_usd": 8.020625,
"generation_cost_usd": 3.430312,
"grading_cost_usd": 4.590313,
"mean_delta_pass_rate": 0.01666666666666668,
"mean_delta_tokens": -308.625,
"mean_delta_time_seconds": 4.609374999999999,
"mean_delta_cost_usd": 0.03610633333333333,
"models_improved": 0,
"models_neutral": 3,
"models_degraded": 0
},
"baseline_comparison": {
"path": "skills/redis-core/evals/core/baselines/aggregate-benchmark.json",
"generated_at": "2026-05-20T07:02:10.439Z",
"input_root": "eval-workspaces/redis-development/data-structures-key-naming/iteration-1",
"overall": {
"baseline": {
"mean_pass_delta": 0.01666666666666668,
"mean_token_delta": -221.875,
"mean_time_delta_seconds": 8.221208333333333,
"mean_cost_delta_usd": 0.058316
},
"current": {
"mean_pass_delta": 0.01666666666666668,
"mean_token_delta": -308.625,
"mean_time_delta_seconds": 4.609374999999999,
"mean_cost_delta_usd": 0.03610633333333333
},
"change": {
"mean_pass_delta": 0,
"mean_token_delta": -86.75,
"mean_time_delta_seconds": -3.611833333333334,
"mean_cost_delta_usd": -0.02220966666666667
}
},
"models": [
{
"model": "claude-haiku-4-5-20251001",
"status": "compared",
"baseline": {
"pass_delta": 0.025000000000000022,
"token_delta": -63.25,
"time_delta_seconds": 11.909374999999997,
"cost_delta_usd": 0.045928
},
"current": {
"pass_delta": 0,
"token_delta": -75.375,
"time_delta_seconds": 9.172125,
"cost_delta_usd": 0.041595
},
"change": {
"pass_delta": -0.025000000000000022,
"token_delta": -12.125,
"time_delta_seconds": -2.7372499999999977,
"cost_delta_usd": -0.004332999999999997
},
"baseline_verdict": "neutral",
"current_verdict": "neutral"
},
{
"model": "claude-opus-4-7",
"status": "compared",
"baseline": {
"pass_delta": 0,
"token_delta": -587,
"time_delta_seconds": 4.516875000000002,
"cost_delta_usd": 0.074996
},
"current": {
"pass_delta": 0.025000000000000022,
"token_delta": -713.875,
"time_delta_seconds": -1.4606250000000003,
"cost_delta_usd": 0.028464
},
"change": {
"pass_delta": 0.025000000000000022,
"token_delta": -126.875,
"time_delta_seconds": -5.977500000000003,
"cost_delta_usd": -0.04653199999999999
},
"baseline_verdict": "neutral",
"current_verdict": "neutral"
},
{
"model": "claude-sonnet-4-6",
"status": "compared",
"baseline": {
"pass_delta": 0.025000000000000022,
"token_delta": -15.375,
"time_delta_seconds": 8.237375,
"cost_delta_usd": 0.054024
},
"current": {
"pass_delta": 0.025000000000000022,
"token_delta": -136.625,
"time_delta_seconds": 6.116624999999999,
"cost_delta_usd": 0.03826
},
"change": {
"pass_delta": 0,
"token_delta": -121.25,
"time_delta_seconds": -2.120750000000001,
"cost_delta_usd": -0.015764
},
"baseline_verdict": "neutral",
"current_verdict": "neutral"
}
],
"missing_models": []
}
}
Skill Benchmark
Generated: 2026-05-22T10:36:23.032Z
Skill: redis-core
Suite: core
Input: eval-workspaces/redis-core/core/iteration-1
Overall
- Models: 3
- Mean pass-rate delta: +2 points
- Mean token delta: -309
- Mean time delta: +4.6s
- Total eval cost: $8.0206
- Mean cost delta: +$0.0361
- Verdict counts: 0 improves, 3 neutral, 0 degrades
Against Baseline
Baseline: skills/redis-core/evals/core/baselines/aggregate-benchmark.json
Baseline generated: 2026-05-20T07:02:10.439Z
| Metric | Baseline | Current | Change |
|---|---|---|---|
| Mean pass delta | +2 points | +2 points | +0 points |
| Mean token delta | -222 | -309 | -87 |
| Mean time delta | +8.2s | +4.6s | -3.6s |
| Mean cost delta | +$0.0583 | +$0.0361 | -$0.0222 |
By Model Against Baseline
| Model | Pass Delta Change | Token Delta Change | Time Delta Change | Cost Delta Change | Verdict |
|---|---|---|---|---|---|
| claude-haiku-4-5-20251001 | -3 points | -12 | -2.7s | -$0.0043 | neutral -> neutral |
| claude-opus-4-7 | +3 points | -127 | -6.0s | -$0.0465 | neutral -> neutral |
| claude-sonnet-4-6 | +0 points | -121 | -2.1s | -$0.0158 | neutral -> neutral |
By Model
| Model | Without Skill | With Skill | Pass Delta | Token Delta | Time Delta | Total Cost | Cost Delta | Verdict |
|---|---|---|---|---|---|---|---|---|
| claude-haiku-4-5-20251001 | 95% | 95% | +0 points | -75 | +9.2s | $2.1215 | +$0.0416 | neutral |
| claude-opus-4-7 | 98% | 100% | +3 points | -714 | -1.5s | $3.3557 | +$0.0285 | neutral |
| claude-sonnet-4-6 | 95% | 98% | +3 points | -137 | +6.1s | $2.5435 | +$0.0383 | neutral |
By Eval
| Eval | Without Skill | With Skill | Pass Delta | Token Delta | Time Delta | Model Pass Deltas |
|---|---|---|---|---|---|---|
| object-profile-cache | 87% | 90% | +3 points | -247 | +6.6s | claude-haiku-4-5-20251001: +0 points<br>claude-opus-4-7: +0 points<br>claude-sonnet-4-6: +10 points |
| unique-membership | 97% | 100% | +3 points | -294 | +3.2s | claude-haiku-4-5-20251001: +0 points<br>claude-opus-4-7: +10 points<br>claude-sonnet-4-6: +0 points |
| leaderboard-ranking | 100% | 100% | +0 points | -296 | +5.4s | claude-haiku-4-5-20251001: +0 points<br>claude-opus-4-7: +0 points<br>claude-sonnet-4-6: +0 points |
| key-naming-cleanup | 100% | 100% | +0 points | -397 | +3.2s | claude-haiku-4-5-20251001: +0 points<br>claude-opus-4-7: +0 points<br>claude-sonnet-4-6: +0 points |
{
"baseline_name": "current",
"updated_at": "2026-05-22T10:36:23.051Z",
"skill_name": "redis-core",
"eval_suite": "core",
"iteration": "iteration-1",
"input_root": "eval-workspaces/redis-core/core/iteration-1",
"included_files": [
"aggregate-benchmark.json",
"aggregate-benchmark.md",
"model-matrix.json",
"baseline.json",
"README.md"
]
}
{
"eval_suite": "core",
"description": "Cross-model run plan for the redis-core eval suite (data structure selection and key naming). Anthropic skill-creator tooling owns generation, grading, per-model benchmark.json, and benchmark.md; this file records the model matrix we run before combining per-model benchmark files.",
"models": [
"claude-opus-4-7",
"claude-sonnet-4-6",
"claude-haiku-4-5-20251001"
],
"configurations": ["with_skill", "without_skill"],
"repetitions": 2,
"judge_model": "claude-opus-4-7",
"default_iteration": "iteration-1"
}
core Baseline
Updated: 2026-05-22T10:36:23.051Z
Skill: redis-core
Suite: core
Source iteration: iteration-1
Source output: eval-workspaces/redis-core/core/iteration-1
This is a curated aggregate benchmark snapshot. Use it as the shared reference when comparing future skill changes against the current accepted behavior.
Included Files
aggregate-benchmark.jsonaggregate-benchmark.mdmodel-matrix.jsonbaseline.jsonREADME.md
Update Command
npm run eval:baseline -- --skill redis-core --suite core --iteration iteration-1{
"skill_name": "redis-core",
"eval_suite": "core",
"description": "Core evals for the redis-core skill: data structure selection and key naming.",
"evals": [
{
"id": 1,
"name": "object-profile-cache",
"prompt": "I'm caching user profile data in Redis. Each user has id, name, email, plan, and lastLogin. The email and plan fields change independently. I was going to store the whole profile as a JSON string at User_1001_Profile. What Redis data structure and key naming pattern should I use?",
"expected_output": "Recommends a Redis Hash for the flat user profile, explains why field-level updates are useful, and proposes short colon-separated keys such as user:1001:profile.",
"covered_rules": ["data-choose-structure", "data-key-naming"],
"expectations": [
"The output recommends a Redis Hash as the primary structure for the flat user profile fields.",
"The output explains that a Hash supports independent or field-level updates without rewriting the entire object.",
"The output discourages storing this flat profile as a JSON string or opaque string blob.",
"The output includes at least one concise colon-separated key example for the user profile, such as user:1001:profile.",
"The output keeps JSON as optional only for nested or hierarchical data, not as the main recommendation for this prompt."
]
},
{
"id": 2,
"name": "unique-membership",
"prompt": "For an article page, I need to track the unique user IDs that liked the article, quickly check if a user already liked it, and show the total like count. What Redis type and key names would you suggest?",
"expected_output": "Recommends a Redis Set for unique membership, mentions membership/count operations, and uses readable keys such as article:987:likes.",
"covered_rules": ["data-choose-structure", "data-key-naming"],
"expectations": [
"The output recommends a Redis Set as the primary structure for unique user IDs.",
"The output mentions membership and count operations, such as SADD, SISMEMBER, and SCARD, or clearly equivalent Redis operations.",
"The output includes at least one concise colon-separated key example for article likes, such as article:987:likes.",
"The output avoids recommending a List as the primary structure for this uniqueness and membership-check use case.",
"The output is concise and does not introduce unnecessary schemas, indexes, or unrelated Redis features."
]
},
{
"id": 3,
"name": "leaderboard-ranking",
"prompt": "I'm building a game leaderboard in Redis. I need to update player scores, fetch the top 10 players, and find a player's rank. What data structure and key pattern should I use?",
"expected_output": "Recommends a Redis Sorted Set for score-based ranking, mentions score/rank operations, and proposes a key such as game:space-invaders:leaderboard.",
"covered_rules": ["data-choose-structure", "data-key-naming"],
"expectations": [
"The output recommends a Redis Sorted Set as the primary structure for the leaderboard.",
"The output explains that Sorted Sets order members by score.",
"The output mentions score, top-N, or rank operations, such as ZADD, ZREVRANGE, ZRANGE, ZRANK, or ZREVRANK.",
"The output includes at least one concise colon-separated key example for the leaderboard.",
"The output avoids recommending a Hash, List, or Set as the primary structure for score-based ranking."
]
},
{
"id": 4,
"name": "key-naming-cleanup",
"prompt": "Can you clean up these Redis key names and explain the convention? User_1001_Profile, my key with spaces, http://www.example.com/store/products/product.html?id=8361, orderItemsFor2024, tenant42User7Cart",
"expected_output": "Converts the examples to short, readable, colon-separated Redis keys and explains why spaces, inconsistent casing, and very long URL keys are poor choices.",
"covered_rules": ["data-key-naming"],
"expectations": [
"The output uses colon-separated key names with a consistent hierarchy.",
"The output avoids spaces, inconsistent casing, and very long full-URL keys in the proposed replacements.",
"The output proposes extracting a short identifier or using a digest for the long URL key.",
"The output includes concrete replacements for all five provided key names.",
"The output explains that shorter readable keys help maintainability, debugging, or memory usage."
]
}
]
}
{
"eval_suite": "core",
"description": "Cross-model run plan for the redis-core eval suite (data structure selection and key naming). Anthropic skill-creator tooling owns generation, grading, per-model benchmark.json, and benchmark.md; this file records the model matrix we run before combining per-model benchmark files.",
"models": [
"claude-opus-4-7",
"claude-sonnet-4-6",
"claude-haiku-4-5-20251001"
],
"configurations": ["with_skill", "without_skill"],
"repetitions": 2,
"judge_model": "claude-opus-4-7",
"default_iteration": "iteration-1"
}
Choose the Right Data Structure
Selecting the appropriate Redis data type for your use case is fundamental to performance and memory efficiency.
| Use Case | Recommended Type | Why |
|---|---|---|
| Simple values, counters | String | Fast, atomic operations |
| Object with fields | Hash | Memory efficient, partial updates, field-level expiration |
| Queue, recent items | List | O(1) push/pop at ends |
| Unique items, membership | Set | O(1) add/remove/check |
| Rankings, ranges | Sorted Set | Score-based ordering |
| Nested/hierarchical data | JSON | Path queries, nested structures, geospatial indexing with RQE |
| Event logs, messaging | Stream | Persistent, consumer groups |
| Similarity search | Vector Set | Native vector storage with built-in HNSW indexing |
Incorrect: Using strings for everything.
Python (redis-py):
# Storing object as JSON string loses atomic field updates
redis.set("user:1001", json.dumps({"name": "Alice", "email": "alice@example.com"}))
# To update email, must fetch, parse, modify, and rewrite entire object
user = json.loads(redis.get("user:1001"))
user["email"] = "new@example.com"
redis.set("user:1001", json.dumps(user))Java (Jedis):
// Bad: Storing as delimited string requires manual parsing
jedis.set("bicycle", "Deimos;Ergonom;Enduro bikes;4972");
String bike = jedis.get("bicycle");
String[] fields = bike.split(";");
String model = fields[0]; // Fragile and error-proneCorrect: Use Hash for objects with fields.
Python (redis-py):
# Hash allows atomic field updates
redis.hset("user:1001", mapping={"name": "Alice", "email": "alice@example.com"})
# Update single field without touching others
redis.hset("user:1001", "email", "new@example.com")Java (Jedis):
import java.util.Map;
import java.util.HashMap;
// Good: Hash models properties naturally
Map<String, String> hashFields = new HashMap<>();
hashFields.put("model", "Deimos");
hashFields.put("brand", "Ergonom");
hashFields.put("type", "Enduro bikes");
hashFields.put("price", "4972");
jedis.hset("bicycle", hashFields);
// Read individual field
String model = jedis.hget("bicycle", "model");Reference: Choosing the Right Data Type
Use Consistent Key Naming Conventions
Well-structured key names improve code maintainability, debugging, and enable efficient key scanning.
Correct: Use colons as separators with a consistent hierarchy.
# Pattern: service:entity:id:attribute
user:1001:profile
user:1001:settings
order:2024:items
cache:api:users:list
session:abc123Python (redis-py):
# Good: Short, meaningful key
redis.set("product:8361", cached_html)
page = redis.get("product:8361")Java (Jedis):
// Good: Short, meaningful key derived from URL
jedis.set("product:8361", "<some cached HTML>");
String page = jedis.get("product:8361");Incorrect: Inconsistent naming, spaces, or very long keys.
# These cause confusion and waste memory
User_1001_Profile
my key with spaces
com.mycompany.myapp.production.users.profile.data.1001Java (Jedis):
// Bad: Using full URL as key wastes memory and slows comparisons
jedis.set("http://www.verylongurlkey.com/store/products/product.html?id=8361",
"<some cached HTML>");Key naming tips:
- Keep keys short but readable—they consume memory
- Consider key prefixes for multi-tenant applications
- Extract short identifiers from URLs or long strings rather than using the whole thing
- For large binary values, consider using a hash digest as the key instead of the value itself
- Use consistent separators (colons are conventional)
Reference: Redis Keys
Related skills
FAQ
Which structures are covered?
String, Hash, List, Set, Sorted Set, JSON, Stream, and Vector Set.
What naming convention?
Consistent colon-separated key names across namespaces.
What use cases?
Caching, leaderboards, queues, streams, and vector search patterns.