Refactor(skills): rename prompt modules to skills and update documentation

This commit is contained in:
0xallam
2026-01-06 17:50:15 -08:00
parent f48def1f9e
commit 7af1180a30
43 changed files with 235 additions and 238 deletions

View File

@@ -39,14 +39,14 @@ Thank you for your interest in contributing to Strix! This guide will help you g
poetry run strix --target https://example.com poetry run strix --target https://example.com
``` ```
## 📚 Contributing Prompt Modules ## 📚 Contributing Skills
Prompt modules are specialized knowledge packages that enhance agent capabilities. See [strix/prompts/README.md](strix/prompts/README.md) for detailed guidelines. Skills are specialized knowledge packages that enhance agent capabilities. See [strix/skills/README.md](strix/skills/README.md) for detailed guidelines.
### Quick Guide ### Quick Guide
1. **Choose the right category** (`/vulnerabilities`, `/frameworks`, `/technologies`, etc.) 1. **Choose the right category** (`/vulnerabilities`, `/frameworks`, `/technologies`, etc.)
2. **Create a** `.jinja` file with your prompts 2. **Create a** `.jinja` file with your skill content
3. **Include practical examples** - Working payloads, commands, or test cases 3. **Include practical examples** - Working payloads, commands, or test cases
4. **Provide validation methods** - How to confirm findings and avoid false positives 4. **Provide validation methods** - How to confirm findings and avoid false positives
5. **Submit via PR** with clear description 5. **Submit via PR** with clear description

View File

@@ -219,11 +219,11 @@ export PERPLEXITY_API_KEY="your-api-key" # for search capabilities
## 📚 Documentation ## 📚 Documentation
Full documentation is available at **[docs.strix.ai](https://docs.strix.ai)** — including detailed guides for usage, CI/CD integrations, prompt modules, and advanced configuration. Full documentation is available at **[docs.strix.ai](https://docs.strix.ai)** — including detailed guides for usage, CI/CD integrations, skills, and advanced configuration.
## 🤝 Contributing ## 🤝 Contributing
We welcome contributions of code, docs, and new prompt modules - check out our [Contributing Guide](https://docs.strix.ai/contributing) to get started or open a [pull request](https://github.com/usestrix/strix/pulls)/[issue](https://github.com/usestrix/strix/issues). We welcome contributions of code, docs, and new skills - check out our [Contributing Guide](https://docs.strix.ai/contributing) to get started or open a [pull request](https://github.com/usestrix/strix/pulls)/[issue](https://github.com/usestrix/strix/issues).
## 👥 Join Our Community ## 👥 Join Our Community

View File

@@ -122,7 +122,7 @@ hiddenimports = [
'strix.tools.registry', 'strix.tools.registry',
'strix.tools.executor', 'strix.tools.executor',
'strix.tools.argument_parser', 'strix.tools.argument_parser',
'strix.prompts', 'strix.skills',
] ]
hiddenimports += collect_submodules('litellm') hiddenimports += collect_submodules('litellm')

View File

@@ -8,13 +8,13 @@ class StrixAgent(BaseAgent):
max_iterations = 300 max_iterations = 300
def __init__(self, config: dict[str, Any]): def __init__(self, config: dict[str, Any]):
default_modules = [] default_skills = []
state = config.get("state") state = config.get("state")
if state is None or (hasattr(state, "parent_id") and state.parent_id is None): if state is None or (hasattr(state, "parent_id") and state.parent_id is None):
default_modules = ["root_agent"] default_skills = ["root_agent"]
self.default_llm_config = LLMConfig(prompt_modules=default_modules) self.default_llm_config = LLMConfig(skills=default_skills)
super().__init__(config) super().__init__(config)

View File

@@ -263,25 +263,25 @@ CRITICAL RULES:
- **ONE AGENT = ONE TASK** - Don't let agents do multiple unrelated jobs - **ONE AGENT = ONE TASK** - Don't let agents do multiple unrelated jobs
- **SPAWN REACTIVELY** - Create new agents based on what you discover - **SPAWN REACTIVELY** - Create new agents based on what you discover
- **ONLY REPORTING AGENTS** can use create_vulnerability_report tool - **ONLY REPORTING AGENTS** can use create_vulnerability_report tool
- **AGENT SPECIALIZATION MANDATORY** - Each agent must be highly specialized; prefer 13 prompt modules, up to 5 for complex contexts - **AGENT SPECIALIZATION MANDATORY** - Each agent must be highly specialized; prefer 13 skills, up to 5 for complex contexts
- **NO GENERIC AGENTS** - Avoid creating broad, multi-purpose agents that dilute focus - **NO GENERIC AGENTS** - Avoid creating broad, multi-purpose agents that dilute focus
AGENT SPECIALIZATION EXAMPLES: AGENT SPECIALIZATION EXAMPLES:
GOOD SPECIALIZATION: GOOD SPECIALIZATION:
- "SQLi Validation Agent" with prompt_modules: sql_injection - "SQLi Validation Agent" with skills: sql_injection
- "XSS Discovery Agent" with prompt_modules: xss - "XSS Discovery Agent" with skills: xss
- "Auth Testing Agent" with prompt_modules: authentication_jwt, business_logic - "Auth Testing Agent" with skills: authentication_jwt, business_logic
- "SSRF + XXE Agent" with prompt_modules: ssrf, xxe, rce (related attack vectors) - "SSRF + XXE Agent" with skills: ssrf, xxe, rce (related attack vectors)
BAD SPECIALIZATION: BAD SPECIALIZATION:
- "General Web Testing Agent" with prompt_modules: sql_injection, xss, csrf, ssrf, authentication_jwt (too broad) - "General Web Testing Agent" with skills: sql_injection, xss, csrf, ssrf, authentication_jwt (too broad)
- "Everything Agent" with prompt_modules: all available modules (completely unfocused) - "Everything Agent" with skills: all available skills (completely unfocused)
- Any agent with more than 5 prompt modules (violates constraints) - Any agent with more than 5 skills (violates constraints)
FOCUS PRINCIPLES: FOCUS PRINCIPLES:
- Each agent should have deep expertise in 1-3 related vulnerability types - Each agent should have deep expertise in 1-3 related vulnerability types
- Agents with single modules have the deepest specialization - Agents with single skills have the deepest specialization
- Related vulnerabilities (like SSRF+XXE or Auth+Business Logic) can be combined - Related vulnerabilities (like SSRF+XXE or Auth+Business Logic) can be combined
- Never create "kitchen sink" agents that try to do everything - Never create "kitchen sink" agents that try to do everything
@@ -323,7 +323,7 @@ Example (agent creation tool):
<function=create_agent> <function=create_agent>
<parameter=task>Perform targeted XSS testing on the search endpoint</parameter> <parameter=task>Perform targeted XSS testing on the search endpoint</parameter>
<parameter=name>XSS Discovery Agent</parameter> <parameter=name>XSS Discovery Agent</parameter>
<parameter=prompt_modules>xss</parameter> <parameter=skills>xss</parameter>
</function> </function>
SPRAYING EXECUTION NOTE: SPRAYING EXECUTION NOTE:
@@ -392,12 +392,12 @@ Directories:
Default user: pentester (sudo available) Default user: pentester (sudo available)
</environment> </environment>
{% if loaded_module_names %} {% if loaded_skill_names %}
<specialized_knowledge> <specialized_knowledge>
{# Dynamic prompt modules loaded based on agent specialization #} {# Dynamic skills loaded based on agent specialization #}
{% for module_name in loaded_module_names %} {% for skill_name in loaded_skill_names %}
{{ get_module(module_name) }} {{ get_skill(skill_name) }}
{% endfor %} {% endfor %}
</specialized_knowledge> </specialized_knowledge>

View File

@@ -6,7 +6,7 @@ class LLMConfig:
self, self,
model_name: str | None = None, model_name: str | None = None,
enable_prompt_caching: bool = True, enable_prompt_caching: bool = True,
prompt_modules: list[str] | None = None, skills: list[str] | None = None,
timeout: int | None = None, timeout: int | None = None,
scan_mode: str = "deep", scan_mode: str = "deep",
): ):
@@ -16,7 +16,7 @@ class LLMConfig:
raise ValueError("STRIX_LLM environment variable must be set and not empty") raise ValueError("STRIX_LLM environment variable must be set and not empty")
self.enable_prompt_caching = enable_prompt_caching self.enable_prompt_caching = enable_prompt_caching
self.prompt_modules = prompt_modules or [] self.skills = skills or []
self.timeout = timeout or int(os.getenv("LLM_TIMEOUT", "300")) self.timeout = timeout or int(os.getenv("LLM_TIMEOUT", "300"))

View File

@@ -20,7 +20,7 @@ from strix.llm.config import LLMConfig
from strix.llm.memory_compressor import MemoryCompressor from strix.llm.memory_compressor import MemoryCompressor
from strix.llm.request_queue import get_global_queue from strix.llm.request_queue import get_global_queue
from strix.llm.utils import _truncate_to_first_function, parse_tool_invocations from strix.llm.utils import _truncate_to_first_function, parse_tool_invocations
from strix.prompts import load_prompt_modules from strix.skills import load_skills
from strix.tools import get_tools_prompt from strix.tools import get_tools_prompt
@@ -116,29 +116,29 @@ class LLM:
if agent_name: if agent_name:
prompt_dir = Path(__file__).parent.parent / "agents" / agent_name prompt_dir = Path(__file__).parent.parent / "agents" / agent_name
prompts_dir = Path(__file__).parent.parent / "prompts" skills_dir = Path(__file__).parent.parent / "skills"
loader = FileSystemLoader([prompt_dir, prompts_dir]) loader = FileSystemLoader([prompt_dir, skills_dir])
self.jinja_env = Environment( self.jinja_env = Environment(
loader=loader, loader=loader,
autoescape=select_autoescape(enabled_extensions=(), default_for_string=False), autoescape=select_autoescape(enabled_extensions=(), default_for_string=False),
) )
try: try:
modules_to_load = list(self.config.prompt_modules or []) skills_to_load = list(self.config.skills or [])
modules_to_load.append(f"scan_modes/{self.config.scan_mode}") skills_to_load.append(f"scan_modes/{self.config.scan_mode}")
prompt_module_content = load_prompt_modules(modules_to_load, self.jinja_env) skill_content = load_skills(skills_to_load, self.jinja_env)
def get_module(name: str) -> str: def get_skill(name: str) -> str:
return prompt_module_content.get(name, "") return skill_content.get(name, "")
self.jinja_env.globals["get_module"] = get_module self.jinja_env.globals["get_skill"] = get_skill
self.system_prompt = self.jinja_env.get_template("system_prompt.jinja").render( self.system_prompt = self.jinja_env.get_template("system_prompt.jinja").render(
get_tools_prompt=get_tools_prompt, get_tools_prompt=get_tools_prompt,
loaded_module_names=list(prompt_module_content.keys()), loaded_skill_names=list(skill_content.keys()),
**prompt_module_content, **skill_content,
) )
except (FileNotFoundError, OSError, ValueError) as e: except (FileNotFoundError, OSError, ValueError) as e:
logger.warning(f"Failed to load system prompt for {agent_name}: {e}") logger.warning(f"Failed to load system prompt for {agent_name}: {e}")

View File

@@ -1,64 +0,0 @@
# 📚 Strix Prompt Modules
## 🎯 Overview
Prompt modules are specialized knowledge packages that enhance Strix agents with deep expertise in specific vulnerability types, technologies, and testing methodologies. Each module provides advanced techniques, practical examples, and validation methods that go beyond baseline security knowledge.
---
## 🏗️ Architecture
### How Prompts Work
When an agent is created, it can load up to 5 specialized prompt modules relevant to the specific subtask and context at hand:
```python
# Agent creation with specialized modules
create_agent(
task="Test authentication mechanisms in API",
name="Auth Specialist",
prompt_modules="authentication_jwt,business_logic"
)
```
The modules are dynamically injected into the agent's system prompt, allowing it to operate with deep expertise tailored to the specific vulnerability types or technologies required for the task at hand.
---
## 📁 Module Categories
| Category | Purpose |
|----------|---------|
| **`/vulnerabilities`** | Advanced testing techniques for core vulnerability classes like authentication bypasses, business logic flaws, and race conditions |
| **`/frameworks`** | Specific testing methods for popular frameworks e.g. Django, Express, FastAPI, and Next.js |
| **`/technologies`** | Specialized techniques for third-party services such as Supabase, Firebase, Auth0, and payment gateways |
| **`/protocols`** | Protocol-specific testing patterns for GraphQL, WebSocket, OAuth, and other communication standards |
| **`/cloud`** | Cloud provider security testing for AWS, Azure, GCP, and Kubernetes environments |
| **`/reconnaissance`** | Advanced information gathering and enumeration techniques for comprehensive attack surface mapping |
| **`/custom`** | Community-contributed modules for specialized or industry-specific testing scenarios |
---
## 🎨 Creating New Modules
### What Should a Module Contain?
A good prompt module is a structured knowledge package that typically includes:
- **Advanced techniques** - Non-obvious methods specific to the task and domain
- **Practical examples** - Working payloads, commands, or test cases with variations
- **Validation methods** - How to confirm findings and avoid false positives
- **Context-specific insights** - Environment and version nuances, configuration-dependent behavior, and edge cases
Modules use XML-style tags for structure and focus on deep, specialized knowledge that significantly enhances agent capabilities for that specific context.
---
## 🤝 Contributing
Community contributions are more than welcome — contribute new modules via [pull requests](https://github.com/usestrix/strix/pulls) or [GitHub issues](https://github.com/usestrix/strix/issues) to help expand the collection and improve extensibility for Strix agents.
---
> [!NOTE]
> **Work in Progress** - We're actively expanding the prompt module collection with specialized techniques and new categories.

View File

@@ -1,109 +0,0 @@
from pathlib import Path
from jinja2 import Environment
def get_available_prompt_modules() -> dict[str, list[str]]:
modules_dir = Path(__file__).parent
available_modules = {}
for category_dir in modules_dir.iterdir():
if category_dir.is_dir() and not category_dir.name.startswith("__"):
category_name = category_dir.name
modules = []
for file_path in category_dir.glob("*.jinja"):
module_name = file_path.stem
modules.append(module_name)
if modules:
available_modules[category_name] = sorted(modules)
return available_modules
def get_all_module_names() -> set[str]:
all_modules = set()
for category_modules in get_available_prompt_modules().values():
all_modules.update(category_modules)
return all_modules
def validate_module_names(module_names: list[str]) -> dict[str, list[str]]:
available_modules = get_all_module_names()
valid_modules = []
invalid_modules = []
for module_name in module_names:
if module_name in available_modules:
valid_modules.append(module_name)
else:
invalid_modules.append(module_name)
return {"valid": valid_modules, "invalid": invalid_modules}
def generate_modules_description() -> str:
available_modules = get_available_prompt_modules()
if not available_modules:
return "No prompt modules available"
all_module_names = get_all_module_names()
if not all_module_names:
return "No prompt modules available"
sorted_modules = sorted(all_module_names)
modules_str = ", ".join(sorted_modules)
description = (
f"List of prompt modules to load for this agent (max 5). Available modules: {modules_str}. "
)
example_modules = sorted_modules[:2]
if example_modules:
example = f"Example: {', '.join(example_modules)} for specialized agent"
description += example
return description
def load_prompt_modules(module_names: list[str], jinja_env: Environment) -> dict[str, str]:
import logging
logger = logging.getLogger(__name__)
module_content = {}
prompts_dir = Path(__file__).parent
available_modules = get_available_prompt_modules()
for module_name in module_names:
try:
module_path = None
if "/" in module_name:
module_path = f"{module_name}.jinja"
else:
for category, modules in available_modules.items():
if module_name in modules:
module_path = f"{category}/{module_name}.jinja"
break
if not module_path:
root_candidate = f"{module_name}.jinja"
if (prompts_dir / root_candidate).exists():
module_path = root_candidate
if module_path and (prompts_dir / module_path).exists():
template = jinja_env.get_template(module_path)
var_name = module_name.split("/")[-1]
module_content[var_name] = template.render()
logger.info(f"Loaded prompt module: {module_name} -> {var_name}")
else:
logger.warning(f"Prompt module not found: {module_name}")
except (FileNotFoundError, OSError, ValueError) as e:
logger.warning(f"Failed to load prompt module {module_name}: {e}")
return module_content

64
strix/skills/README.md Normal file
View File

@@ -0,0 +1,64 @@
# 📚 Strix Skills
## 🎯 Overview
Skills are specialized knowledge packages that enhance Strix agents with deep expertise in specific vulnerability types, technologies, and testing methodologies. Each skill provides advanced techniques, practical examples, and validation methods that go beyond baseline security knowledge.
---
## 🏗️ Architecture
### How Skills Work
When an agent is created, it can load up to 5 specialized skills relevant to the specific subtask and context at hand:
```python
# Agent creation with specialized skills
create_agent(
task="Test authentication mechanisms in API",
name="Auth Specialist",
skills="authentication_jwt,business_logic"
)
```
The skills are dynamically injected into the agent's system prompt, allowing it to operate with deep expertise tailored to the specific vulnerability types or technologies required for the task at hand.
---
## 📁 Skill Categories
| Category | Purpose |
|----------|---------|
| **`/vulnerabilities`** | Advanced testing techniques for core vulnerability classes like authentication bypasses, business logic flaws, and race conditions |
| **`/frameworks`** | Specific testing methods for popular frameworks e.g. Django, Express, FastAPI, and Next.js |
| **`/technologies`** | Specialized techniques for third-party services such as Supabase, Firebase, Auth0, and payment gateways |
| **`/protocols`** | Protocol-specific testing patterns for GraphQL, WebSocket, OAuth, and other communication standards |
| **`/cloud`** | Cloud provider security testing for AWS, Azure, GCP, and Kubernetes environments |
| **`/reconnaissance`** | Advanced information gathering and enumeration techniques for comprehensive attack surface mapping |
| **`/custom`** | Community-contributed skills for specialized or industry-specific testing scenarios |
---
## 🎨 Creating New Skills
### What Should a Skill Contain?
A good skill is a structured knowledge package that typically includes:
- **Advanced techniques** - Non-obvious methods specific to the task and domain
- **Practical examples** - Working payloads, commands, or test cases with variations
- **Validation methods** - How to confirm findings and avoid false positives
- **Context-specific insights** - Environment and version nuances, configuration-dependent behavior, and edge cases
Skills use XML-style tags for structure and focus on deep, specialized knowledge that significantly enhances agent capabilities for that specific context.
---
## 🤝 Contributing
Community contributions are more than welcome — contribute new skills via [pull requests](https://github.com/usestrix/strix/pulls) or [GitHub issues](https://github.com/usestrix/strix/issues) to help expand the collection and improve extensibility for Strix agents.
---
> [!NOTE]
> **Work in Progress** - We're actively expanding the skills collection with specialized techniques and new categories.

107
strix/skills/__init__.py Normal file
View File

@@ -0,0 +1,107 @@
from pathlib import Path
from jinja2 import Environment
def get_available_skills() -> dict[str, list[str]]:
skills_dir = Path(__file__).parent
available_skills = {}
for category_dir in skills_dir.iterdir():
if category_dir.is_dir() and not category_dir.name.startswith("__"):
category_name = category_dir.name
skills = []
for file_path in category_dir.glob("*.jinja"):
skill_name = file_path.stem
skills.append(skill_name)
if skills:
available_skills[category_name] = sorted(skills)
return available_skills
def get_all_skill_names() -> set[str]:
all_skills = set()
for category_skills in get_available_skills().values():
all_skills.update(category_skills)
return all_skills
def validate_skill_names(skill_names: list[str]) -> dict[str, list[str]]:
available_skills = get_all_skill_names()
valid_skills = []
invalid_skills = []
for skill_name in skill_names:
if skill_name in available_skills:
valid_skills.append(skill_name)
else:
invalid_skills.append(skill_name)
return {"valid": valid_skills, "invalid": invalid_skills}
def generate_skills_description() -> str:
available_skills = get_available_skills()
if not available_skills:
return "No skills available"
all_skill_names = get_all_skill_names()
if not all_skill_names:
return "No skills available"
sorted_skills = sorted(all_skill_names)
skills_str = ", ".join(sorted_skills)
description = f"List of skills to load for this agent (max 5). Available skills: {skills_str}. "
example_skills = sorted_skills[:2]
if example_skills:
example = f"Example: {', '.join(example_skills)} for specialized agent"
description += example
return description
def load_skills(skill_names: list[str], jinja_env: Environment) -> dict[str, str]:
import logging
logger = logging.getLogger(__name__)
skill_content = {}
skills_dir = Path(__file__).parent
available_skills = get_available_skills()
for skill_name in skill_names:
try:
skill_path = None
if "/" in skill_name:
skill_path = f"{skill_name}.jinja"
else:
for category, skills in available_skills.items():
if skill_name in skills:
skill_path = f"{category}/{skill_name}.jinja"
break
if not skill_path:
root_candidate = f"{skill_name}.jinja"
if (skills_dir / root_candidate).exists():
skill_path = root_candidate
if skill_path and (skills_dir / skill_path).exists():
template = jinja_env.get_template(skill_path)
var_name = skill_name.split("/")[-1]
skill_content[var_name] = template.render()
logger.info(f"Loaded skill: {skill_name} -> {var_name}")
else:
logger.warning(f"Skill not found: {skill_name}")
except (FileNotFoundError, OSError, ValueError) as e:
logger.warning(f"Failed to load skill {skill_name}: {e}")
return skill_content

View File

@@ -190,36 +190,35 @@ def create_agent(
task: str, task: str,
name: str, name: str,
inherit_context: bool = True, inherit_context: bool = True,
prompt_modules: str | None = None, skills: str | None = None,
) -> dict[str, Any]: ) -> dict[str, Any]:
try: try:
parent_id = agent_state.agent_id parent_id = agent_state.agent_id
module_list = [] skill_list = []
if prompt_modules: if skills:
module_list = [m.strip() for m in prompt_modules.split(",") if m.strip()] skill_list = [s.strip() for s in skills.split(",") if s.strip()]
if len(module_list) > 5: if len(skill_list) > 5:
return { return {
"success": False, "success": False,
"error": ( "error": (
"Cannot specify more than 5 prompt modules for an agent " "Cannot specify more than 5 skills for an agent (use comma-separated format)"
"(use comma-separated format)"
), ),
"agent_id": None, "agent_id": None,
} }
if module_list: if skill_list:
from strix.prompts import get_all_module_names, validate_module_names from strix.skills import get_all_skill_names, validate_skill_names
validation = validate_module_names(module_list) validation = validate_skill_names(skill_list)
if validation["invalid"]: if validation["invalid"]:
available_modules = list(get_all_module_names()) available_skills = list(get_all_skill_names())
return { return {
"success": False, "success": False,
"error": ( "error": (
f"Invalid prompt modules: {validation['invalid']}. " f"Invalid skills: {validation['invalid']}. "
f"Available modules: {', '.join(available_modules)}" f"Available skills: {', '.join(available_skills)}"
), ),
"agent_id": None, "agent_id": None,
} }
@@ -240,7 +239,7 @@ def create_agent(
if hasattr(parent_agent.llm_config, "scan_mode"): if hasattr(parent_agent.llm_config, "scan_mode"):
scan_mode = parent_agent.llm_config.scan_mode scan_mode = parent_agent.llm_config.scan_mode
llm_config = LLMConfig(prompt_modules=module_list, timeout=timeout, scan_mode=scan_mode) llm_config = LLMConfig(skills=skill_list, timeout=timeout, scan_mode=scan_mode)
agent_config = { agent_config = {
"llm_config": llm_config, "llm_config": llm_config,

View File

@@ -79,8 +79,8 @@ Only create a new agent if no existing agent is handling the specific task.</des
<parameter name="inherit_context" type="boolean" required="false"> <parameter name="inherit_context" type="boolean" required="false">
<description>Whether the new agent should inherit parent's conversation history and context</description> <description>Whether the new agent should inherit parent's conversation history and context</description>
</parameter> </parameter>
<parameter name="prompt_modules" type="string" required="false"> <parameter name="skills" type="string" required="false">
<description>Comma-separated list of prompt modules to use for the agent (MAXIMUM 5 modules allowed). Most agents should have at least one module in order to be useful. Agents should be highly specialized - use 1-3 related modules; up to 5 for complex contexts. {{DYNAMIC_MODULES_DESCRIPTION}}</description> <description>Comma-separated list of skills to use for the agent (MAXIMUM 5 skills allowed). Most agents should have at least one skill in order to be useful. Agents should be highly specialized - use 1-3 related skills; up to 5 for complex contexts. {{DYNAMIC_SKILLS_DESCRIPTION}}</description>
</parameter> </parameter>
</parameters> </parameters>
<returns type="Dict[str, Any]"> <returns type="Dict[str, Any]">
@@ -92,30 +92,30 @@ Only create a new agent if no existing agent is handling the specific task.</des
<parameter=task>Validate and exploit the suspected SQL injection vulnerability found in <parameter=task>Validate and exploit the suspected SQL injection vulnerability found in
the login form. Confirm exploitability and document proof of concept.</parameter> the login form. Confirm exploitability and document proof of concept.</parameter>
<parameter=name>SQLi Validator</parameter> <parameter=name>SQLi Validator</parameter>
<parameter=prompt_modules>sql_injection</parameter> <parameter=skills>sql_injection</parameter>
</function> </function>
<function=create_agent> <function=create_agent>
<parameter=task>Test authentication mechanisms, JWT implementation, and session management <parameter=task>Test authentication mechanisms, JWT implementation, and session management
for security vulnerabilities and bypass techniques.</parameter> for security vulnerabilities and bypass techniques.</parameter>
<parameter=name>Auth Specialist</parameter> <parameter=name>Auth Specialist</parameter>
<parameter=prompt_modules>authentication_jwt, business_logic</parameter> <parameter=skills>authentication_jwt, business_logic</parameter>
</function> </function>
# Example of single-module specialization (most focused) # Example of single-skill specialization (most focused)
<function=create_agent> <function=create_agent>
<parameter=task>Perform comprehensive XSS testing including reflected, stored, and DOM-based <parameter=task>Perform comprehensive XSS testing including reflected, stored, and DOM-based
variants across all identified input points.</parameter> variants across all identified input points.</parameter>
<parameter=name>XSS Specialist</parameter> <parameter=name>XSS Specialist</parameter>
<parameter=prompt_modules>xss</parameter> <parameter=skills>xss</parameter>
</function> </function>
# Example of up to 5 related modules (borderline acceptable) # Example of up to 5 related skills (borderline acceptable)
<function=create_agent> <function=create_agent>
<parameter=task>Test for server-side vulnerabilities including SSRF, XXE, and potential <parameter=task>Test for server-side vulnerabilities including SSRF, XXE, and potential
RCE vectors in file upload and XML processing endpoints.</parameter> RCE vectors in file upload and XML processing endpoints.</parameter>
<parameter=name>Server-Side Attack Specialist</parameter> <parameter=name>Server-Side Attack Specialist</parameter>
<parameter=prompt_modules>ssrf, xxe, rce</parameter> <parameter=skills>ssrf, xxe, rce</parameter>
</function> </function>
</examples> </examples>
</tool> </tool>

View File

@@ -23,17 +23,17 @@ class ImplementedInClientSideOnlyError(Exception):
def _process_dynamic_content(content: str) -> str: def _process_dynamic_content(content: str) -> str:
if "{{DYNAMIC_MODULES_DESCRIPTION}}" in content: if "{{DYNAMIC_SKILLS_DESCRIPTION}}" in content:
try: try:
from strix.prompts import generate_modules_description from strix.skills import generate_skills_description
modules_description = generate_modules_description() skills_description = generate_skills_description()
content = content.replace("{{DYNAMIC_MODULES_DESCRIPTION}}", modules_description) content = content.replace("{{DYNAMIC_SKILLS_DESCRIPTION}}", skills_description)
except ImportError: except ImportError:
logger.warning("Could not import prompts utilities for dynamic schema generation") logger.warning("Could not import skills utilities for dynamic schema generation")
content = content.replace( content = content.replace(
"{{DYNAMIC_MODULES_DESCRIPTION}}", "{{DYNAMIC_SKILLS_DESCRIPTION}}",
"List of prompt modules to load for this agent (max 5). Module discovery failed.", "List of skills to load for this agent (max 5). Skill discovery failed.",
) )
return content return content