# How to Customize Agent System Prompts and Behavior in Strix: A Complete Guide

> Discover how to customize agent system prompts and behavior in Strix 🚀 Learn to pass context dictionaries or override methods for tailored agent interactions. Your complete guide awaits!

- Repository: [Strix/strix](https://github.com/usestrix/strix)
- Tags: how-to-guide
- Published: 2026-03-26

---

**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`](https://github.com/usestrix/strix/blob/main/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`](https://github.com/usestrix/strix/blob/main/strix/agents/StrixAgent/strix_agent.py) |
| **LLMConfig** | Configuration dataclass that accepts an optional `system_prompt_context` dictionary for static customization. | [`strix/llm/config.py`](https://github.com/usestrix/strix/blob/main/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:

1. **`StrixAgent.__init__`** calls `_build_system_scope_context(scan_config)` to generate a dictionary describing the current scan configuration.
2. The agent passes this dictionary to `llm.set_system_prompt_context(context)`, which stores the runtime context.
3. **`StrixLLM.set_system_prompt_context`** triggers `_load_system_prompt()` to re-render the Jinja2 template with the updated context.
4. 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.

```jinja
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`](https://github.com/usestrix/strix/blob/main/strix/llm/config.py) accepts a `system_prompt_context` parameter.

```python
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.

```python
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`](https://github.com/usestrix/strix/blob/main/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.

```python

# 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`](https://github.com/usestrix/strix/blob/main/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:

```python
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:

```jinja
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 initializing `StrixLLM` in [`strix/llm/llm.py`](https://github.com/usestrix/strix/blob/main/strix/llm/llm.py).
- **Dynamic customization** requires subclassing `StrixAgent` and overriding `_build_system_scope_context()` to inject scan-specific data before the agent calls `set_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`](https://github.com/usestrix/strix/blob/main/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`](https://github.com/usestrix/strix/blob/main/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.