Map Requirement
Map rules to a single requirement in a control file. This is the atomic unit of the mapping workflow — it finds candidate rules, presents them to the author, and writes the selection back to the control file.
Tool Strategy
This skill uses mcp__content-agent__* tools when available (preferred — deterministic, structured results). When the MCP server is not configured, fall back to filesystem-based alternatives noted as Fallback in each step. See .claude/skills/shared/mcp_fallbacks.md for detailed fallback procedures. The skill must complete successfully either way.
Without MCP server: Cross-framework similarity search is unavailable. Candidate rules will be found by keyword search only, which may miss semantically similar but differently-worded requirements.
Arguments: $ARGUMENTS — format: <control_id> <requirement_id> --product <product_id> [--policy <path>]
Examples:
/map-requirement anssi R3 --product rhel9/map-requirement srg_gpos SRG-OS-000001-GPOS-00001 --product rhel10/map-requirement hipaa 164.312(a)(1) --product rhel9/map-requirement anssi R34 --product rhel9 --policy security_policies/anssi_2.md
Phase 1: Parse and Validate
Parse arguments: Extract
control_id,requirement_id,--productflag, and optional--policyflag from$ARGUMENTS.If no
--productspecified, discover available products and ask the user viaAskUserQuestion:- Run
ls products/(or callmcp__content-agent__list_products) to get the list of available products - "Which product are you mapping rules for?"
- Options: present the most common products from the discovered list + Other
- Run
Check build artifacts: Call
mcp__content-agent__list_built_products.- If the target product is NOT in the built list, ask the user via
AskUserQuestion:- "Product '{product}' has not been built yet. Rule search works best with build artifacts (expanded Jinja templates). Build it now?"
- Options:
- "Yes, build now (Recommended)" — description: "Runs
/build-product {product} --datastream-onlybefore starting the mapping session" - "No, continue without build" — description: "Rule search will use raw source files, which may miss some rules due to Jinja template parsing errors"
- "Yes, build now (Recommended)" — description: "Runs
- If user chooses to build, invoke the
build-productskill:Skill(skill="build-product", args="{product} --datastream-only"). Wait for the build to complete before continuing. - Fallback: Check if
build/{product}/rules/directory exists. If not, offer the build prompt above.
- If the target product is NOT in the built list, ask the user via
Load the requirement: Call
mcp__content-agent__get_control_detailswithcontrol_id.- If control not found, call
mcp__content-agent__list_controlsand show options. - Find the requirement matching
requirement_idin the controls list. - If requirement not found, list available requirement IDs and ask user to pick.
- Fallback: Read the control YAML directly from
controls/<control_id>.ymlorproducts/<product>/controls/<control_id>.yml. If the file hascontrols_dir:, read individual requirement files from that directory. To list controls, runls controls/*.ymlandls products/*/controls/*.yml.
- If control not found, call
Display the requirement:
## Requirement: {requirement_id} **Title**: {title} **Description**: {description} **Current status**: {status} **Current rules**: {rules or "none"}If no
--policyspecified, show a tip:Tip: Pass
--policy <path>to enrich mapping with the original security policy text (PDF, Markdown, HTML). This improves cross-framework matching accuracy.
Phase 1.5: Policy Enrichment (if --policy provided)
If --policy was specified:
Infer document type from the file extension:
.md→markdown.pdf→pdf.html→html- Otherwise →
text
Call
mcp__content-agent__parse_policy_documentwith:source: the policy pathdocument_type: inferred from extensionrequirement_id: the requirement ID from Phase 1- Fallback: For markdown/text files, read the file directly and search for the requirement ID. For PDF files, inform the user that PDF parsing requires the MCP server.
If sections returned, display the policy context:
### Policy Context (from {policy_path}) **{section_title}** {section_content} {subsection contents...}Store the combined section text as
policy_textfor use in Phase 2.
Phase 2: Find Candidate Rules
Execute steps 2a-2c to build a candidate list from multiple sources.
Step 2a: Cross-Framework Search
Call mcp__content-agent__find_similar_requirements with:
requirement_text: ifpolicy_textis available, use it; otherwise use the requirement's title + " " + descriptionexclude_control_id: current control_idmax_results: 10
Fallback: Extract 3-5 key terms from the requirement text. Use Grep to search for each term across controls/*.yml and products/*/controls/*.yml. Requirements matching multiple terms are likely similar. Read matched requirements to extract their rules: lists.
If results found, present them grouped by control framework:
### Similar Requirements in Other Frameworks
- [{control_id}] {requirement_id}: "{title}" → rules: {rules}
- [{control_id}] {requirement_id}: "{title}" → rules: {rules}
Extract the union of all rules from similar requirements as "cross-framework candidates".
Step 2b: Rule Search in Build Artifacts
Search for candidate rules using rendered build artifacts (Jinja-expanded, product-specific):
Extract 3-5 key terms from the requirement title and description.
For each key term, call
mcp__content-agent__search_rendered_contentwith:query: the key termproduct: the target product from Phase 1limit: 15- Fallback: If the product is not built, use
Grepto search for key terms inrule.ymlfiles underlinux_os/guide/andapplications/. This may miss rules with Jinja-templated descriptions.
Deduplicate results across all term searches. Combine with cross-framework candidates from Step 2a.
For each candidate rule, use
mcp__content-agent__get_rendered_rule(orget_rule_details) to read its title and description. Reason about which rules best match the requirement:- Look for rules whose title/description semantically matches the requirement
- Prioritize rules that also appeared in Step 2a cross-framework results
- Consider rule severity alignment with the requirement's intent
- Rank candidates by relevance
Present the top candidates in a table:
### Rule Candidates | Rule ID | Title | Source | Reasoning | |---------|-------|--------|-----------| | {rule_id} | {title} | cross-ref / search | {why it matches} |
Step 2c: Product Availability Check
Since search_rendered_content only returns rules present in the target product's build, all search results are already confirmed available. For cross-framework candidates (from Step 2a) that did NOT appear in the rendered search, call mcp__content-agent__get_rule_product_availability to verify availability.
Fallback: For each rule, find its rule.yml and check the identifiers: section for cce@<product> entries. Also grep for the rule ID in products/<target_product>/profiles/*.profile and products/<target_product>/controls/*.yml.
Flag rules that are NOT available for the target product:
Warning: Rule '{rule_id}' has identifiers for {other_products} but NOT for {target_product}.
May need platform/identifier additions to work for {target_product}.
For rules missing from the target product, use LLM judgment to assess portability:
- If the rule uses a template (
templateis not None in get_rule_details), it's likely portable - If it has platform constraints mentioning specific products, note the constraint
- Optionally call
mcp__content-agent__get_rule_detailswithrendered_detail=fullandproduct=<a product that has it>to read the actual OVAL/remediation and assess whether it's product-specific
Phase 3: Author Decision
Build unified candidate list: Combine cross-framework and search candidates, deduplicated by rule_id, sorted by relevance.
Present candidates using
AskUserQuestionwithmultiSelect: true:- "Select rules to map to requirement '{requirement_id}: {title}'"
- Options: top candidates (up to 4, the AskUserQuestion limit), each with description showing source (cross-framework, search, or both) and reasoning
- If more than 4 candidates, present top 3 + "Show more candidates"
Ask about status using a separate
AskUserQuestion:- "How should this requirement be marked?"
- Options:
- "Automated" — rules fully cover the requirement
- "Partially automated" — rules cover some aspects
- "Not applicable" — requirement doesn't apply to this product
- "Skip for now" — don't change anything
Phase 4: Write Selection
Based on author's decision:
If rules were selected (automated or partially_automated):
Call
mcp__content-agent__update_requirement_ruleswith:control_id: the control file IDrequirement_id: the requirement IDrules: the selected rule IDsstatus: "automated" or "partially_automated" based on author's choice- Fallback: Find the requirement file using
get_requirement_file_pathfallback (see above). UseEdittool to update therules:andstatus:fields in the YAML. Be careful to preserve existing formatting, comments, and Jinja2 templating.
Verify the result:
- Check
successfield in the response - If failed, report the error and suggest manual editing
- Check
Report:
Updated requirement '{requirement_id}' in '{control_id}': - Rules: {rules} - Status: {status} - File: {file_path}
If marked not applicable:
Call
mcp__content-agent__update_requirement_ruleswith:control_id: the control file IDrequirement_id: the requirement IDrules: [] (empty list)status: "not_applicable"- Fallback: Edit the requirement YAML directly to set
status: not_applicableandrules: [].
Report the change.
If skipped:
Report that no changes were made and move on.
Phase 5: Summary
Present a brief summary:
## Mapping Complete
Requirement: {requirement_id} ({title})
Control file: {control_id}
Action: {mapped N rules / marked not applicable / skipped}
File modified: {file_path or "none"}
Next steps:
- Map another requirement: `/map-requirement {control_id} <next_req_id> --product {product}`
- Map all unmapped: `/map-controls {control_id} --product {product}`
- Review changes: `git diff controls/`
Error Handling
- If
update_requirement_rulesfails, display the error message and suggest the user manually edit the file. Usemcp__content-agent__get_requirement_file_pathto find the correct file, or Fallback: locate it by reading the control YAML'scontrols_dir:field or searching for the requirement in the inlinecontrols:list. - If rule search returns no results, rely only on cross-framework candidates from step 2a.
- If no candidates are found from any source, inform the user and offer options: "Skip", "Enter rule IDs manually", "Create new rule (use /create-rule)".