How to Customize Agent System Prompts and Behavior in Strix: A Complete Guide
Strix agents rely on a Jinja2-based system prompt template that you can customize by passing a context dictionary via LLMConfig.system_prompt_context or by overriding the _build_system_scope_context() method in a custom agent subclass.
Strix is an open-source security automation framework that utilizes LLM-powered agents to perform security scans. The behavior and role of these agents are governed by a system prompt that provides context about the scan configuration, target environment, and operational constraints. Understanding how to customize agent system prompts and behavior in Strix allows you to tailor the underlying language model's responses to specific organizational policies, compliance requirements, or domain-specific analysis needs.
Architecture of System Prompts in Strix
The system prompt mechanism in Strix involves four coordinated components that work together during agent initialization and runtime.
Core Components
| Component | Responsibility | Source File |
|---|---|---|
| StrixLLM | Loads the Jinja2 template, renders it with runtime context, and stores the final system_prompt string injected into every LLM request. |
strix/llm/llm.py |
| StrixAgent | Assembles scan-specific context (target URLs, enabled tools, scan metadata) and passes it to the LLM wrapper. | strix/agents/StrixAgent/strix_agent.py |
| LLMConfig | Configuration dataclass that accepts an optional system_prompt_context dictionary for static customization. |
strix/llm/config.py |
| system_prompt.jinja | The static Jinja2 template skeleton containing placeholders like {{ system_prompt_context }} that are populated at runtime. |
strix/agents/StrixAgent/system_prompt.jinja |
Initialization Flow
When you instantiate a Strix agent, the following sequence occurs:
StrixAgent.__init__calls_build_system_scope_context(scan_config)to generate a dictionary describing the current scan configuration.- The agent passes this dictionary to
llm.set_system_prompt_context(context), which stores the runtime context. StrixLLM.set_system_prompt_contexttriggers_load_system_prompt()to re-render the Jinja2 template with the updated context.- Every subsequent LLM request includes a system message:
[{"role": "system", "content": self.system_prompt}].
Methods to Customize Agent System Prompts
You can customize the system prompt at three different levels: template modification, static configuration, or dynamic runtime injection.
1. Modify the Jinja2 Template
For permanent structural changes to the prompt skeleton, edit the template file directly. The base template at strix/agents/StrixAgent/system_prompt.jinja contains placeholders that get populated at runtime.
You are a security‑analysis agent. {{ system_prompt_context }}
You will receive findings and must respond with JSON following the schema...
To add new variables, insert Jinja2 syntax like {{ org_name }} or {{ compliance_framework }} into the template, then ensure these keys exist in the context dictionary passed to the LLM.
2. Inject Context via LLMConfig (Static Configuration)
The simplest method for adding custom data without modifying source files is to provide a context dictionary when constructing the StrixLLM instance. The LLMConfig class in strix/llm/config.py accepts a system_prompt_context parameter.
from strix.llm.config import LLMConfig
from strix.llm.llm import StrixLLM
custom_context = {
"org_name": "Acme Corp",
"severity_threshold": "high",
"compliance_mode": "PCI-DSS"
}
config = LLMConfig(system_prompt_context=custom_context, model="gpt-4")
llm = StrixLLM(config=config, agent_name="compliance-agent")
This approach is ideal for global configuration values that remain constant across all scans performed by this LLM instance.
3. Override Agent Methods for Dynamic Context
For scan-specific customization, subclass StrixAgent and override the _build_system_scope_context(scan_config) method. This allows you to inject dynamic data based on the specific target or scan configuration.
from strix.agents.StrixAgent import StrixAgent
class PolicyAwareAgent(StrixAgent):
def _build_system_scope_context(self, scan_config):
# Retrieve default context from parent class
base_context = super()._build_system_scope_context(scan_config)
# Add scan-specific variables
base_context.update({
"org_name": "Acme Corp",
"company_policy": (
"All findings must be reported in the internal ticketing system. "
"Only 'critical' severity findings should be escalated immediately."
),
"scan_environment": scan_config.get("environment", "production")
})
return base_context
When the agent initializes, it automatically calls self.llm.set_system_prompt_context() (as implemented at line 62 in strix/agents/StrixAgent/strix_agent.py) with your enriched dictionary, ensuring the LLM receives the customized prompt.
Refreshing Prompts at Runtime
If you need to modify the system prompt after the agent has already processed requests, you can manually update the context by calling the setter method on the LLM instance. This triggers a re-render of the template.
# Update context dynamically during execution
new_context = {
"org_name": "Acme Corp",
"emergency_mode": True
}
agent.llm.set_system_prompt_context(new_context)
According to the implementation in strix/llm/llm.py (lines 147-151), this setter stores the new dictionary and invokes _load_system_prompt() again, updating self.system_prompt for all subsequent LLM calls.
Practical Example: Enforcing Company Policies
Here is a complete implementation combining template customization with dynamic context injection to enforce specific reporting policies:
from strix.llm.config import LLMConfig
from strix.llm.llm import StrixLLM
from strix.agents.StrixAgent import StrixAgent
# Step 1: Define static context
static_context = {
"org_name": "Acme Corp",
"severity_threshold": "high"
}
# Step 2: Configure LLM with static context
config = LLMConfig(
system_prompt_context=static_context,
model="gpt-4",
temperature=0.1
)
llm = StrixLLM(config=config, agent_name="policy-agent")
# Step 3: Create agent subclass with dynamic policy injection
class PolicyEnforcementAgent(StrixAgent):
def _build_system_scope_context(self, scan_config):
ctx = super()._build_system_scope_context(scan_config)
ctx["company_policy"] = (
"All findings must be reported in the internal ticketing system. "
"Only 'critical' severity findings should be escalated immediately."
)
ctx["scan_type"] = scan_config.get("scan_type", "vulnerability")
return ctx
# Step 4: Instantiate and run
agent = PolicyEnforcementAgent(llm=llm, scan_config={"target": "https://example.com"})
In your system_prompt.jinja file, you can now reference these variables:
You are {{ org_name }}'s security agent performing a {{ scan_type }} scan.
Policy: {{ company_policy }}
Severity threshold: {{ severity_threshold }}
{{ system_prompt_context }}
Summary
- Strix uses a Jinja2 template (
system_prompt.jinja) as the foundation for agent system prompts, rendered with runtime context variables. - Static customization is achieved via
LLMConfig.system_prompt_context, passing a dictionary when initializingStrixLLMinstrix/llm/llm.py. - Dynamic customization requires subclassing
StrixAgentand overriding_build_system_scope_context()to inject scan-specific data before the agent callsset_system_prompt_context(). - Template modification allows structural changes to the prompt skeleton by editing
strix/agents/StrixAgent/system_prompt.jinja. - Runtime updates are possible by calling
agent.llm.set_system_prompt_context(new_context), which triggers re-rendering via_load_system_prompt().
Frequently Asked Questions
What file contains the base system prompt template in Strix?
The base system prompt template is located at strix/agents/StrixAgent/system_prompt.jinja. This Jinja2 template contains the static skeleton of the prompt, including placeholders like {{ system_prompt_context }} that get populated with runtime data from the agent or configuration object.
How do I add custom variables to the system prompt without modifying Strix source code?
Pass a dictionary to the system_prompt_context parameter when creating an LLMConfig instance, as defined in strix/llm/config.py. Alternatively, subclass StrixAgent and override _build_system_scope_context() to dynamically inject variables based on scan configuration. Both methods update the rendering context without requiring changes to the core library files.
Can I change the system prompt after the agent has started processing?
Yes. Call agent.llm.set_system_prompt_context(new_dict) to update the context dictionary. According to the implementation in strix/llm/llm.py, this setter updates the stored context and re-renders the template by invoking _load_system_prompt(), ensuring subsequent LLM requests use the updated system prompt.
What is the difference between system_prompt_context and modifying the Jinja template?
system_prompt_context provides data that fills placeholders within the existing template structure, ideal for injecting values like company names or policies. Modifying the Jinja template itself (system_prompt.jinja) changes the static structure and wording of the prompt, allowing you to add new sections or alter the fundamental instructions given to the LLM.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →