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

# plurai.config.yaml

> Reference for plurai.config.yaml, the file that describes your agent, its tools and its mock environment.

`plurai_sim/plurai.config.yaml` is the one configuration file for a simulated agent. The scan writes most of it from your agent's code, and you review it on the mocking map. A few keys are answers only you can give, and the plugin never writes them for you.

Commit this file. It is the same on every machine and in every clone.

## Keys you set

These keys record your decisions. The scan carries them over unchanged when it rewrites the file.

### `anonymize`

| Type | Default | Written by |
| - | - | - |
| boolean | absent, which means raw | The first command that uploads data asks you once and writes your answer. |

Sets the anonymization posture for this Environment. With `true`, every upload scrubs personal data on your machine before it leaves. With `false` or absent, data is uploaded as-is, under the Terms of Service and the Privacy Policy you accepted at sign-up.

```yaml theme={null}
anonymize: true
```

`true` requires the `plurai[anonymize]` extra and a spaCy English model. Without them, uploads refuse to run. After an Environment has uploaded under one posture, switching to the other is refused: start a new Environment instead. See [Data and privacy](https://docs.plurai.ai/security/data-and-privacy.md).

### `approve_harness_edits`

| Type | Default | Written by |
| - | - | - |
| boolean | absent, which means `false` | You only. |

Approves, in advance, fixes to the Harness when nobody is there to answer, for example in CI. When someone can be asked, the plugin always asks. With `false` or absent, those fixes stay unapplied and appear in the Report.

```yaml theme={null}
approve_harness_edits: true
```

The value must be a YAML boolean. A quoted `"true"` approves nothing. The approval covers `simulate.py` and the runner declared in `harness.entry_wrapper`.

### `workspace`

| Type | Default | Written by |
| - | - | - |
| string, or a mapping with `name` and `run_driver` | `run_driver: interactive` | The scan writes the name. You set `run_driver`. |

Names the workspace. The mapping form also says who runs the commands. With `run_driver: headless`, every question the flow would ask takes its declared default, and anything only a person can supply (a key, credentials) stops the flow with a finding instead of a guess.

```yaml Interactive (default) theme={null}
workspace: acme
```

```yaml Headless theme={null}
workspace:
  name: acme
  run_driver: headless   # interactive | headless
```

`PLURAI_SIM_NONINTERACTIVE=1` in the environment does the same as `run_driver: headless`. An explicit `run_driver: interactive` wins over the variable.

## Keys the scan writes

Review these on the mocking map. Change them by saying what is wrong in chat, or by re-running `/simulation-scan-agent`, rather than by hand.

### `project`

String. The name of the project under test.

### `shape`

| Type | Default |
| - | - |
| `dialog` or `pipeline` | `dialog` when the Harness exposes a conversation entry point |

How the runner drives your agent. `dialog` runs a conversation. `pipeline` sends one structured input and reads one structured output.

### `agent`

Mapping. Where your agent lives and how it is built: `framework`, `module`, `graph_variable`, `state_class`, `checkpointer`, `entry_point`.

```yaml theme={null}
agent:
  framework: langgraph
  module: our_backend.agents.billing
  graph_variable: graph
  state_class: AgentState
  checkpointer: memory
  entry_point: fetch_context
```

### `agent_context`

Mapping. The fields your agent expects before the first turn, such as the signed-in user. Each field under `fields` has a `type`, `required` and `description`. `precondition: true` means scenario generation must fill it with a non-empty, coherent value.

```yaml theme={null}
agent_context:
  fields:
    user_id: { type: string, required: true, description: "UUID of the active user" }
```

### `agent.io`

Mapping, optional. What your agent can be handed in a message. Omit it for an agent that takes plain text and never opens the conversation.

| Key | Type | Meaning |
| - | - | - |
| `input` | list of `text`, `image_url`, `file` | The message parts the agent accepts. An agent that is handed documents must list `file`. |
| `may_open` | boolean | The agent can start the conversation with no user message. |
| `opens` | `always` | Your product opens every conversation, so turn 0 is the agent's greeting. Implies `may_open: true`. |

```yaml theme={null}
agent.io:
  input: [text, file]
  may_open: false
```

The key is the literal root key `agent.io`, not `io` nested under `agent`.

### `tools`

Mapping of tool name to its declaration. The most important field is `mode`:

| `mode` | What happens in a Run |
| - | - |
| `mock` | The mock environment answers the call. Nothing reaches production. |
| `real` | The tool's real code runs. Use it for read-only sources such as a public knowledge index. |
| `observe` | The tool runs for real and its results are captured into the world state, so mocked tools can use them. |

Each tool also carries a `descriptor` (description, arguments, return fields, business rules, error cases) that the backend uses to generate a faithful mock.

```yaml theme={null}
tools:
  get_user_profile:
    mode: mock
    descriptor:
      description: "Fetch user profile from production Postgres users table"
      args:
        user_id: { type: str, description: "UUID of the user" }
  rag_search:
    mode: observe
```

### `render_actions`

List of strings. Actions your agent emits that are not tool calls, such as showing a table or an image. `render_actions: []` declares that there are none.

```yaml theme={null}
render_actions: [show_invoice_table, show_receipt_image]
```

### `world_state`

Mapping. The records the mock environment holds and how they are reset.

| Key | Type | Default | Meaning |
| - | - | - | - |
| `entity_types` | mapping | | Each record type, its `fields` (every field states `required`), and optional default records. |
| `owner` | `mock`, `agent` or `external` | `mock` | Who owns the state a scenario changes. With `agent` or `external`, `simulate.py` must export a `reset()` function, or the Run refuses to start. |
| `slots` | integer | | With `agent` or `external`: how many identical copies of the store exist, so attempts can run in parallel. |
| `owned_types` | list | | In a split world, the record types your own store holds. The mock holds the rest. |
| `user_surfaces` | list | absent | What a person sees in your product (screens) or receives from it (email, text messages, notifications). `[]` means nothing reaches the user outside the chat. |

```yaml theme={null}
world_state:
  entity_types:
    user:
      description: "User account"
      fields:
        id: { type: string, required: true }
        plan: { type: string, enum: [free, pro, enterprise], required: true }
```

### `harness`

Mapping, optional. Declares a runner of your own that `simulate.py` imports to reach the agent.

```yaml theme={null}
harness:
  entry_wrapper: ../run_bench.py   # relative to plurai_sim/
```

The runner then counts as part of the Harness. It appears on the mocking map, the same consent covers edits to it, and an edit to it marks earlier Runs stale. Adding the declaration marks the existing Runs stale once.

### Other scan-managed keys

| Key | Meaning |
| - | - |
| `knowledge` | A record of a closed set of documents pasted into your agent's prompt. Nothing reads it as configuration. |
| `closed_class_detectors` | Optional patterns that recognize members of a closed set (an order code, a product SKU). They are validated against your own sources and refused if they match your own prose. |
| `tool_graph` | How tools connect through shared records. |
| `guards` | Middleware or guards in your agent that read a tool's result or a store. |
| `stubs` | Modules and environment variables stubbed at import time so the agent loads without production infrastructure. |
| `egress` | Production hosts the Run blocks. It sits in a managed block that the scan rewrites. `egress.allow_hosts` is the one value you may set: hosts you deliberately leave reachable. |
| `scanned_at` | When the scan ran. |
| `knowledge_out_of_audience` | For a hosted Agentforce agent: `include` or `exclude` knowledge articles published outside the agent's audience. Written when you answer the question. |

## Next steps

> [card] [Scan your agent](https://docs.plurai.ai/guides/scan-your-agent.md)
>
> How the scan writes this file.

> [card] [Data and privacy](https://docs.plurai.ai/security/data-and-privacy.md)
>
> What `anonymize` changes.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.