redis/domain-pack-authoring
Use when creating, validating, or extending demo business domains in this repo. Covers the required DomainPack contract, fixed folder layout, scaffold command, validation flow, smoke testing, and the rules for keeping framework code separate from domain-specific code.
npx skills add https://github.com/redis/redis-iris-demos --skill domain-pack-authoring
Use this skill when the task is to add a new business domain, refactor an existing domain pack, or check that a domain follows the repo contract.
Reference domains (read these for patterns):
domains/reddash/ — food delivery (canonical reference for standard patterns)domains/radish-bank/ — banking (custom internal tools, hyphenated domain ID)domains/electrohub/ — electronics retail (rich product catalog with vector search)domains/healthcare/ — patient portal (simpler entity schema)domains/finance-researcher/ — market analysis (timeseries, UiConfig, watchlists)uv run python scripts/create_domain.py <domain-id> unless the domain already exists.domains/<domain-id>/ unless the task explicitly changes shared framework code.domains/<domain-id>/domain.py.domains/<domain-id>/schema.py.domains/<domain-id>/prompt.py.domains/<domain-id>/data_generator.py.domains/<domain-id>/docs/demo_paths.md.domains/<domain-id>/presentations/.domain.py:guardrail — a GuardrailConfig with 20-55 on-topic route references + 15-20 off-topic references (see Guardrail Routes below)seed_memories — at least 2 SeedMemory entries for the demo user (personal preferences the agent can recall)seed_langcache — at least 1 SeedLangCacheEntry for a common question (must match a "Cached" starter prompt)branding.theme.landing_bg — a hex color for the landing page background matching the domain's visual identitybranding.demo_steps — exactly 4 strings (Context question, Memory store, "Click Memory", Memory recall)branding.starter_prompts — 4-5 PromptCard objects (2 Context, 2 Memory, 1 Cached)10. Create landing page background SVGs under frontend/public/backgrounds/<domain-id>/:
left.svg (~590×817) and right.svg (~632×817)11. Run validation and smoke tests:
uv run python scripts/validate_domain.py --domain <domain-id>
uv run python scripts/generate_models.py --domain <domain-id>
uv run python scripts/smoke_domain.py --domain <domain-id>
12. If shared framework changes were required, run repo tests before finishing.
Every domain must use this structure:
domains/<domain-id>/
__init__.py
domain.py
schema.py
prompt.py
data_generator.py
assets/logo.<svg|png|jpg|jpeg|webp>
docs/demo_paths.md
Landing page backgrounds:
frontend/public/backgrounds/<domain-id>/
left.svg
right.svg
Generated files:
domains/<domain-id>/generated_models.py
output/<domain-id>/
Optional docs and collateral:
domains/<domain-id>/presentations/
If the domain ID contains hyphens (e.g., radish-bank), Python cannot use standard imports. These domains must use importlib to load sub-modules. See domains/radish-bank/domain.py for the pattern. Prefer unhyphenated IDs when possible.
domains/<domain-id>/domain.py must export DOMAIN.DOMAIN must satisfy the shared contract in backend/app/core/domain_contract.py.manifest.manifest.branding.logo_path may point to any supported image asset under domains/<domain-id>/assets/.manifest.guardrail must define a GuardrailConfig with routes (see Guardrail Routes below).manifest.seed_memories must include at least 2 long-term memories for the demo user (preferences, history).manifest.seed_langcache must include at least 1 cached response. Its prompt must be semantically close to a "Cached" starter prompt card so the demo shows a cache hit.manifest.branding.theme.landing_bg must be a hex color that complements the domain's accent palette.build_system_promptget_internal_tool_definitionsexecute_internal_toolwrite_dataset_metagenerate_demo_datavalidateGuardrails use semantic routing via vector similarity. Reference phrases are embedded into a Redis vector index. When a user message arrives, it is embedded and compared against all references. If the closest match is the allowed route above its distance threshold, the message passes — otherwise it is blocked.
This means references must be written in the language real customers actually use. Formal or technical descriptions will not match casual user messages.
distance_threshold: 0.7)Cover these categories:
Conversational fillers must be on-topic. Without these, simple follow-ups get blocked:
"Yes", "No", "Sure", "Thanks", "Hello", "Hi there", "Can you help me?",
"Tell me more", "Go ahead", "That's all, thanks", "OK", "Got it",
"Yes please", "No thanks", "What else can you help with?"
Write in first person — these are things a customer says:
Include natural variations of the same intent:
distance_threshold: 0.5)Standard set (reuse across domains):
"What's the weather like today?", "Tell me a joke", "Help me with my homework",
"Explain quantum physics", "Write me a Python script", "Translate this to Spanish",
"Who won the Super Bowl?", "Write a poem about love", "What's the meaning of life?",
"Help me debug my React code", "Plan a vacation to Hawaii"
Add 2-3 domain-adjacent off-topic phrases — things that sound related but are outside scope:
Every domain must register at least these internal tools in get_internal_tool_definitions:
get_current_user_profile — returns the signed-in user's identity (ID, name, email). Uses manifest.identity for env var names, defaults, and id_field. Set identity.id_field to the domain-appropriate field name (e.g. "patient_id", "customer_id").get_current_time — returns the current UTC timestamp in ISO 8601. The agent needs this to compare against dates in the data.dataset_overview — returns record counts per entity. Useful for the agent to understand the data scope.execute_internal_tool must handle all three tool names and return dicts.
Optional domain-specific tools handle state-changing operations (not data retrieval — MCP tools handle that). See domains/radish-bank/domain.py for examples: place_fixed_deposit, buy_accident_insurance, request_annual_card_fee_waiver.
The system prompt built by prompt.py must follow this structure (see domains/reddash/prompt.py for the canonical pattern):
value parameter rule (mandatory)This rule MUST appear in every prompt. Without it, the LLM passes field names as parameter keys (e.g. patient_id="P001" instead of value="P001"), which the MCP server rejects silently. The agent receives empty results and tells the user data is unavailable.
Use the dynamic pattern from domains/reddash/prompt.py lines 7-24: build a tool_names set from mcp_tools, then include hints only for tools that exist. This ensures the prompt stays accurate regardless of which MCP tools are available.
The memory tools block and memory rules are conditional on memory_enabled. Copy the pattern from domains/reddash/prompt.py lines 28-42. Instruct the agent that pre-loaded memory context is already in the conversation — search_customer_memory should only be called when the user explicitly asks about past preferences.
Adapt tone to the domain (warm for food delivery, professional for healthcare, formal for banking, analytical for finance). All domains share: 2-3 sentences max, markdown bold for key facts, never expose internal IDs or UTC timestamps.
generate_demo_data defaults to update_env_file=False. Only the scripts/generate_data.py pipeline and direct main() invocation should pass update_env_file=True.main() guard at the bottom of data_generator.py, it must pass update_env_file=True explicitly.DEMO_USER_ID must match manifest.identity.default_id.datetime.now(timezone.utc) so data stays fresh.OPENAI_API_KEY and fall back to fake_embedding. Copy from domains/reddash/data_generator.py lines 32-44.docs/demo_paths.md so an agent or human can run the demo consistently.domains/<domain-id>/presentations/.All text — guardrail routes, seed memories, demo data, starter prompts — must read as if written by or for a real customer of that vertical.
backend/app/* or frontend/src/*.scripts/; extend the generic scripts instead.backend/app/context_surfaces/; keep them inside the domain package.Do not consider the task complete if any of these remain:
ENTITY_SPECSvalidate_domain.py failssmoke_domain.py failsget_internal_tool_definitions returns an empty tuplevalue parameter hint for MCP toolsgenerate_demo_data still defaults update_env_file=TrueAny as relationship type annotations (run make generate-models DOMAIN=<id> to regenerate)GuardrailConfig in manifest)seed_memories list)seed_langcache list)landing_bg in theme configfrontend/public/backgrounds/<domain-id>/left.svg and right.svg)branding.demo_steps does not have exactly 4 entriesbranding.starter_prompts does not have 4-5 entries (2 Context, 2 Memory, 1 Cached)Read references/checklist.md when you need the exact file-by-file checklist.
Take redis/domain-pack-authoring from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.