> ## Documentation Index
> Fetch the complete documentation index at: https://vijil-vijil-sdk-docs.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom Harnesses

> Create targeted evaluations with custom Harnesses, personas, and policies.

While Vijil has a variety of pre-configured [Harnesses](/concepts/evaluation-components/harness) that you can select from, you can also create your own Harnesses in order to obtain a [Trust Score](/concepts/trust-score/introduction) specific to your organization and agent.

## View Custom Harnesses

You can view previously created custom Harnesses by navigating to **Harnesses** in the left sidebar.

To view the prompts, [Personas](/owner-guide/simulate-environment/personas) and [Policies](/owner-guide/simulate-environment/policies) in a custom Harness, click on its row in the **Harnesses** table.

## Create a Custom Harness

1. In the left sidebar, navigate to **Harnesses** and press **Create Harness**.
2. Enter a Harness name and a description.
3. Select an [Agent](/owner-guide/register-agents/what-is-an-agent)
4. <Badge>Optional</Badge> Select one or more [Persona(s)](/owner-guide/simulate-environment/personas).
5. <Badge>Optional</Badge> Select one or more [Policies](/owner-guide/simulate-environment/policies)

## Create a Custom Harness Programmatically

### Create Personas and Policies

[Personas](/owner-guide/simulate-environment/personas) define *who* interacts with your Agent, and [Policies](/owner-guide/simulate-environment/policies) define the *rules* it must follow. Both are optional inputs to custom Harness creation: pass their IDs (`persona_ids` and `policy_ids`) in the next step, and Vijil generates [Probes](/concepts/evaluation-components/probe) that combine each Persona's behavior with each Policy's constraints. Create them first, then reference their IDs when you create the Harness.

<Tabs>
  <Tab title="CLI">
    ```bash theme={null}
    # Create a Persona (or copy a built-in one: vijil persona from-preset <preset_id>)
    vijil persona create \
      --name "Frustrated Customer" \
      --role "End user" \
      --intent adversarial

    # Create a Policy from text, then activate it for use in Harnesses
    vijil policy create \
      --name "Data Handling Policy" \
      --category privacy \
      --source-text "The agent must not store or repeat personal data."

    vijil policy activate <policy_id>
    ```

    Each command prints the new `id`. Save the Persona and Policy IDs for the next step. List built-in options with `vijil persona preset-list` and `vijil policy preset-list`.
  </Tab>

  <Tab title="MCP">
    With the [Vijil MCP server](/developer-guide/agentic/quickstart) configured, ask Claude Code in natural language:

    <Prompt description="Create an adversarial 'Frustrated Customer' persona and a privacy policy that forbids storing personal data">
      Create an adversarial 'Frustrated Customer' persona and a privacy policy that forbids storing personal data
    </Prompt>

    Claude creates the Persona and Policy and returns their IDs.
  </Tab>

  <Tab title="REST API">
    ```bash theme={null}
    curl -s -X POST "$VIJIL_URL/v1/personas/?team_id=$TEAM_ID" \
      -H "Authorization: Bearer $TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "name": "Frustrated Customer",
        "role": "End user",
        "intent": "adversarial"
      }'

    curl -s -X POST "$VIJIL_URL/v1/policies/?team_id=$TEAM_ID" \
      -H "Authorization: Bearer $TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "name": "Data Handling Policy",
        "category": "privacy",
        "source_text": "The agent must not store or repeat personal data."
      }'
    ```

    Each request returns `201 Created` with an `id`. Save both for the next step.
  </Tab>

  <Tab title="SDK">
    ```python theme={null}
    persona = client.personas.create(
        name="Frustrated Customer",
        role="End user",
        intent="adversarial",
    )

    policy = client.policies.create(
        name="Data Handling Policy",
        category="privacy",
        source_text="The agent must not store or repeat personal data.",
    )

    print(persona.id, policy.id)
    ```

    `intent` is one of `benign`, `curious`, `adversarial`, or `malicious`. `category` is one of `privacy`, `ethics`, `security`, `compliance`, `operational`, `brand`, or `custom`.
  </Tab>
</Tabs>

<Tip>
  Personas and Policies are reusable across Harnesses. For balanced coverage, combine a benign and an adversarial Persona with the Policies that matter most to your Agent. See [Define Personas](/owner-guide/simulate-environment/personas) and [Define Policies](/owner-guide/simulate-environment/policies) for design guidance.
</Tip>

### Create a Harness

Pass the Persona and Policy IDs from the previous step as `persona_ids` and `policy_ids`. Both are optional — omit them to generate a Harness from the Agent description alone.

<Tabs>
  <Tab title="CLI">
    ```bash theme={null}
    vijil harness custom-create \
      --name "Customer Support Harness" \
      --agent-id "$AGENT_ID" \
      --persona-ids '["<persona-id>"]' \
      --policy-ids '["<policy-id>"]'
    ```

    | Flag              | Description                                       | Required |
    | ----------------- | ------------------------------------------------- | -------- |
    | `--name`          | Harness display name                              | Yes      |
    | `--agent-id`      | Agent ID to generate Probes for                   | Yes      |
    | `--description`   | Harness description                               |          |
    | `--persona-ids`   | Persona IDs to include (JSON array)               |          |
    | `--policy-ids`    | Policy IDs to include (JSON array)                |          |
    | `--system-prompt` | Agent description or system prompt for generation |          |
    | `--json`          | Output as JSON                                    |          |
  </Tab>

  <Tab title="MCP">
    With the [Vijil MCP server](/developer-guide/agentic/quickstart) configured, ask Claude Code in natural language:

    <Prompt description="Create a custom Harness called 'Customer Support Harness' for agent a1b2c3d4-… with the GDPR policy">
      Create a custom Harness called 'Customer Support Harness' for agent a1b2c3d4-… with the GDPR policy
    </Prompt>

    Claude creates the Harness and returns the ID.
  </Tab>

  <Tab title="REST API">
    Send a `POST` request to `/v1/custom-harnesses/` with your Agent ID. Personas and Policies are optional.

    ```bash theme={null}
    curl -s -X POST "$VIJIL_URL/v1/custom-harnesses/?team_id=$TEAM_ID" \
      -H "Authorization: Bearer $TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "name": "My Custom Harness",
        "description": "Targeted evaluation for our customer-facing agent.",
        "agent_id": "<agent-id>",
        "persona_ids": ["<persona-id>"],
        "policy_ids": ["<policy-id>"],
        "system_prompt": "You are a helpful customer support assistant."
      }'
    ```

    The API returns `201 Created` with the new Harness object. Save the `id` for later calls.

    ```json theme={null}
    {
      "id": "h1a2b3c4-...",
      "team_id": "t1a2b3c4-...",
      "name": "My Custom Harness",
      "agent_id": "<agent-id>",
      "persona_ids": ["<persona-id>"],
      "policy_ids": ["<policy-id>"],
      "status": "draft"
    }
    ```

    | Field           | Description                                                                                | Required |
    | --------------- | ------------------------------------------------------------------------------------------ | -------- |
    | `name`          | Harness display name (1–255 characters)                                                    | Yes      |
    | `agent_id`      | UUID of the Agent under test                                                               | Yes      |
    | `policy_ids`    | One or more Policy UUID values                                                             | No       |
    | `persona_ids`   | One or more Persona UUID values                                                            | No       |
    | `description`   | Human-readable description                                                                 | No       |
    | `system_prompt` | System prompt used during Harness generation; defaults to the Agent description if omitted | No       |
  </Tab>

  <Tab title="SDK">
    ```python theme={null}
    harness = client.harnesses.create(
        name="Customer Support Harness",
        agent_id="<agent-id>",
        persona_ids=["<persona-id>"],   # optional
        policy_ids=["<policy-id>"],     # optional
        system_prompt="You are a helpful customer support assistant.",  # optional
    )
    print(harness.id)
    ```

    | Parameter       | Description                                                             | Required |
    | --------------- | ----------------------------------------------------------------------- | -------- |
    | `name`          | Harness display name                                                    | Yes      |
    | `agent_id`      | UUID of the Agent under test                                            | Yes      |
    | `persona_ids`   | List of Persona UUID values                                             | No       |
    | `policy_ids`    | List of Policy UUID values                                              | No       |
    | `system_prompt` | System prompt used during generation; defaults to the Agent description | No       |
  </Tab>
</Tabs>

<Note>Custom Harnesses are immutable once created. To change the configuration, delete the Harness and create a new one.</Note>

### Check Generation Status

Harness generation is asynchronous. Poll until `status` is `active`.

<CodeGroup>
  ```bash title="CLI" theme={null}
  vijil harness custom-get <harness_id>
  ```

  ```bash title="API" theme={null}
  curl -s "$VIJIL_URL/v1/custom-harnesses/$HARNESS_ID?team_id=$TEAM_ID" \
    -H "Authorization: Bearer $TOKEN"
  ```

  ```python title="SDK" theme={null}
  harness = client.harnesses.show("<harness-id>")
  print(harness.status)
  ```
</CodeGroup>

| `status` value               | Meaning                             |
| ---------------------------- | ----------------------------------- |
| `draft` (no workflow)        | Not yet started                     |
| `draft` (workflow `running`) | Generation in progress              |
| `draft` (workflow `failed`)  | Generation failed                   |
| `active`                     | Ready to use in an Evaluation       |
| `failed`                     | Harness creation failed permanently |

### Get Harness Prompts

Retrieve the generated Probes for a completed Harness.

<CodeGroup>
  ```bash title="CLI" theme={null}
  vijil harness custom-prompts <harness_id> --json
  ```

  ```bash title="API" theme={null}
  curl -s "$VIJIL_URL/v1/custom-harnesses/$HARNESS_ID/prompts?team_id=$TEAM_ID" \
    -H "Authorization: Bearer $TOKEN"
  ```

  ```python title="SDK" theme={null}
  # No dedicated resource method yet — reach the endpoint through the client's HTTP transport
  prompts = client._http.get(
      f"/v1/custom-harnesses/{harness_id}/prompts",
      params={"team_id": team_id},
  )
  ```
</CodeGroup>

Returns an empty list if the Harness is still in `draft` status. The SDK has no dedicated `prompts` method yet, so the example above calls the endpoint through `client._http`, the same transport the high-level methods use.

### List Custom Harnesses

<CodeGroup>
  ```bash title="CLI" theme={null}
  vijil harness custom-list
  vijil harness custom-list --agent-id "$AGENT_ID" --status active
  ```

  ```bash title="API" theme={null}
  curl -s "$VIJIL_URL/v1/custom-harnesses/?team_id=$TEAM_ID&status=active" \
    -H "Authorization: Bearer $TOKEN"
  ```

  ```python title="SDK" theme={null}
  for harness in client.harnesses.list().items:
      print(harness.id, harness.name, harness.status)
  ```
</CodeGroup>

Both support filtering by `agent_id` and `status`, with `limit` and `offset` for pagination. The SDK's `client.harnesses.list()` returns standard and custom Harnesses together.

### Cancel Generation

Stop a Harness that is still generating.

<CodeGroup>
  ```bash title="CLI" theme={null}
  vijil harness custom-cancel <harness_id>
  ```

  ```bash title="API" theme={null}
  curl -s -X POST "$VIJIL_URL/v1/custom-harnesses/$HARNESS_ID/cancel?team_id=$TEAM_ID" \
    -H "Authorization: Bearer $TOKEN"
  ```

  ```python title="SDK" theme={null}
  # No dedicated resource method yet — reach the endpoint through the client's HTTP transport
  client._http.post(
      f"/v1/custom-harnesses/{harness_id}/cancel",
      params={"team_id": team_id},
  )
  ```
</CodeGroup>

The SDK has no dedicated `cancel` method yet, so the example above calls the endpoint through `client._http`, the same transport the high-level methods use.

### Delete a Harness

<CodeGroup>
  ```bash title="CLI" theme={null}
  vijil harness custom-delete <harness_id>
  vijil harness custom-delete <harness_id> --yes
  ```

  ```bash title="API" theme={null}
  curl -s -X DELETE "$VIJIL_URL/v1/custom-harnesses/$HARNESS_ID?team_id=$TEAM_ID" \
    -H "Authorization: Bearer $TOKEN"
  ```

  ```python title="SDK" theme={null}
  client.harnesses.delete("<harness-id>")
  ```
</CodeGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Run Evaluations" icon="play" href="/developer-guide/evaluate/running-evaluations">
    Execute custom Harness evaluations
  </Card>

  <Card title="Understand Results" icon="chart-bar" href="/developer-guide/evaluate/understanding-results">
    Analyze custom Harness results
  </Card>

  <Card title="Personas" icon="users" href="/owner-guide/simulate-environment/personas">
    Learn more about personas
  </Card>

  <Card title="Policies" icon="scroll" href="/owner-guide/simulate-environment/policies">
    Learn more about policies
  </Card>
</CardGroup>
